Skip to content

Commit ee394a9

Browse files
feat: add request_throttle_interval plugin option
1 parent b134918 commit ee394a9

File tree

3 files changed

+98
-99
lines changed

3 files changed

+98
-99
lines changed

src/constants/index.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ export const IS_PROD = process.env.NODE_ENV === "production";
66
export const REQUEST_URL_SLUG = "/api/episerver";
77
export const REQUEST_ACCEPT_HEADER = "application/json";
88
export const REQUEST_TIMEOUT = 30000;
9-
export const REQUEST_THROTTLE_INTERVAL = 1500;
10-
export const REQUEST_MAX_COUNT = 5;
9+
export const REQUEST_THROTTLE_INTERVAL = 3000;
1110

1211
// Auth
1312
export const AUTH_REQUEST_CONTENT_TYPE_HEADER = "application/x-www-form-urlencoded";

src/gatsby-node.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use strict";
22

3-
import { ACCESS_CONTROL_ALLOW_CREDENTIALS, ACCESS_CONTROL_ALLOW_HEADERS, CORS_ORIGIN, REQUEST_TIMEOUT, REQUEST_URL_SLUG } from "./constants";
3+
import { ACCESS_CONTROL_ALLOW_CREDENTIALS, ACCESS_CONTROL_ALLOW_HEADERS, CORS_ORIGIN, REQUEST_THROTTLE_INTERVAL, REQUEST_TIMEOUT, REQUEST_URL_SLUG } from "./constants";
44
import Auth from "./utils/auth";
55
import { convertObjectToString, convertStringToLowercase } from "./utils/convertValues";
66
import { logger } from "./utils/logger";
@@ -91,7 +91,8 @@ exports.pluginOptionsSchema = ({ Joi }) =>
9191
.description("The endpoints to create nodes for"),
9292
log_level: Joi.string().default("debug").description("The log level to use"),
9393
response_type: Joi.string().default("json").description("The response type to use"),
94-
request_timeout: Joi.number().default(REQUEST_TIMEOUT).description("The request timeout to use in milliseconds")
94+
request_timeout: Joi.number().default(REQUEST_TIMEOUT).description("The request timeout to use in milliseconds"),
95+
request_throttle_interval: Joi.number().default(REQUEST_THROTTLE_INTERVAL).description("The request throttle interval to use in milliseconds")
9596
});
9697

9798
/**
@@ -115,7 +116,8 @@ exports.sourceNodes = async ({ actions, cache, createNodeId, createContentDigest
115116
endpoints = null,
116117
log_level = "debug",
117118
response_type = "json",
118-
request_timeout = REQUEST_TIMEOUT
119+
request_timeout = REQUEST_TIMEOUT,
120+
request_throttle_interval = REQUEST_THROTTLE_INTERVAL
119121
} = pluginOptions;
120122

121123
// Custom logger based on the `log_level` plugin option
@@ -154,7 +156,8 @@ exports.sourceNodes = async ({ actions, cache, createNodeId, createContentDigest
154156
"Access-Control-Allow-Origin": CORS_ORIGIN
155157
}),
156158
log,
157-
request_timeout
159+
request_timeout,
160+
request_throttle_interval
158161
});
159162

160163
for (const [nodeName, endpoint] of Object.entries(endpoints)) {

src/utils/optimizely.js

Lines changed: 90 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use strict";
22

33
import sleep from "sleep-promise";
4-
import { CONTENT_ENDPOINT, REQUEST_THROTTLE_INTERVAL } from "../constants";
4+
import { CONTENT_ENDPOINT } from "../constants";
55
import { Request } from "./request";
66

77
export class Optimizely {
@@ -15,6 +15,7 @@ export class Optimizely {
1515
this.headers = config.headers;
1616
this.log = config.log;
1717
this.request_timeout = config.request_timeout;
18+
this.request_throttle_interval = config.request_throttle_interval;
1819
}
1920

2021
// Handle API requests
@@ -28,7 +29,7 @@ export class Optimizely {
2829
});
2930

3031
// Run request
31-
const response = sleep(REQUEST_THROTTLE_INTERVAL)
32+
const response = sleep(this.request_throttle_interval)
3233
.then(async () => await request.run(method, path, body))
3334
.catch((err) => err);
3435

@@ -39,30 +40,42 @@ export class Optimizely {
3940

4041
values.map(async (value) => {
4142
if (value && Object.prototype.hasOwnProperty.call(value, "contentLink") && Object.keys(value)?.length > 0) {
42-
if (typeof value.contentLink.id === "number") {
43-
const response = sleep(REQUEST_THROTTLE_INTERVAL)
44-
.then(async () => await request.run("get", CONTENT_ENDPOINT + value.contentLink.id + "?expand=*", body))
45-
.catch((err) => err);
46-
47-
promises.push(response);
43+
if (value.contentLink.id) {
44+
promises.push(request.run("get", CONTENT_ENDPOINT + value.contentLink.id + "?expand=*", body));
4845
} else {
49-
throw new Error("Expanded `contentLink` in `" + label + "` is missing `id` key");
46+
let message = "Expanded `contentLink` in `" + label + "` is missing `id` key";
47+
48+
throw message;
5049
}
5150
} else {
52-
throw new Error("Expanded `" + label + "` is missing `contentLink` key");
53-
}
51+
let message = "Expanded `" + label + "` is missing `contentLink` key";
5452

55-
return value;
53+
throw message;
54+
}
5655
});
56+
57+
await Promise.allSettled(promises)
58+
.then((res) => {
59+
if (res && Array.isArray(res) && res?.length > 0) {
60+
res
61+
.filter(({ status, value }) => status === "fulfilled" && value !== null)
62+
.map(({ value }, index) => {
63+
const { data } = value;
64+
65+
values[index] = data;
66+
67+
return values[index];
68+
});
69+
}
70+
71+
return Promise.resolve(values);
72+
})
73+
.catch((err) => Promise.reject(err));
5774
} else if (values && Object.prototype.toString.call(values) === "[object Object]" && Object.keys(values)?.length > 0) {
5875
let promises = [];
5976

6077
if (values && Object.prototype.hasOwnProperty.call(values, "id") && Object.keys(values)?.length > 0) {
61-
const response = sleep(REQUEST_THROTTLE_INTERVAL)
62-
.then(async () => await request.run("get", CONTENT_ENDPOINT + values.id + "?expand=*", body))
63-
.catch((err) => err);
64-
65-
promises.push(response);
78+
promises.push(request.run("get", CONTENT_ENDPOINT + values.id + "?expand=*", body));
6679
} else {
6780
let message = "Expanded `" + label + "` is missing `id` key";
6881

@@ -72,13 +85,15 @@ export class Optimizely {
7285
await Promise.allSettled(promises)
7386
.then((res) => {
7487
if (res && Array.isArray(res) && res?.length > 0) {
75-
res.map(({ value = null }) => {
76-
const { data } = value;
88+
res
89+
.filter(({ status, value }) => status === "fulfilled" && value !== null)
90+
.map(({ value }) => {
91+
const { data } = value;
7792

78-
values = data;
93+
values = data;
7994

80-
return values;
81-
});
95+
return values;
96+
});
8297
}
8398

8499
return Promise.resolve(values);
@@ -113,44 +128,54 @@ export class Optimizely {
113128
await Promise.allSettled(expandedKeyValuesPromises)
114129
.then((res) => {
115130
if (res && Array.isArray(res) && res?.length > 0) {
116-
res.map(({ value }, index) => {
117-
switch (index) {
118-
case 0: {
119-
delete temp.contentLink.expanded.dynamicStyles;
120-
temp.contentLink.expanded.dynamicStyles = value;
121-
break;
122-
}
123-
case 1: {
124-
delete temp.contentLink.expanded.items;
125-
temp.contentLink.expanded.items = value;
126-
break;
127-
}
128-
case 2: {
129-
delete temp.contentLink.expanded.images;
130-
temp.contentLink.expanded.images = value;
131-
break;
132-
}
133-
case 3: {
134-
delete temp.contentLink.expanded.form;
135-
temp.contentLink.expanded.form = value;
136-
break;
131+
res
132+
.filter(({ status, value }) => status === "fulfilled" && value !== null)
133+
.map(({ value }, index) => {
134+
switch (index) {
135+
case 0: {
136+
delete temp.contentLink.expanded.dynamicStyles;
137+
temp.contentLink.expanded.dynamicStyles = value;
138+
break;
139+
}
140+
case 1: {
141+
delete temp.contentLink.expanded.items;
142+
temp.contentLink.expanded.items = value;
143+
break;
144+
}
145+
case 2: {
146+
delete temp.contentLink.expanded.images;
147+
temp.contentLink.expanded.images = value;
148+
break;
149+
}
150+
case 3: {
151+
delete temp.contentLink.expanded.form;
152+
temp.contentLink.expanded.form = value;
153+
break;
154+
}
155+
default:
156+
break;
137157
}
138-
default:
139-
break;
140-
}
141158

142-
return temp;
143-
});
159+
return temp;
160+
});
144161

145162
return Promise.resolve(temp);
146163
}
147164
})
148-
.catch((err) => Promise.reject(err));
165+
.catch((err) => {
166+
this.log.error(`An error occurred while fetching content blocks from the Optimizely/Episerver API`, err.message);
167+
168+
return Promise.reject(err);
169+
});
149170

150171
return temp;
151172
})
152173
)
153-
.then((res) => (res && Array.isArray(res) && res?.length > 0 ? res.map(({ value }) => Promise.resolve(value)) : Promise.resolve(res)))
174+
.then((res) => {
175+
if (res && Array.isArray(res) && res?.length > 0) {
176+
return Promise.resolve(res.filter(({ status, value }) => status === "fulfilled" && value !== null).map(({ value }) => value));
177+
}
178+
})
154179
.catch((err) => Promise.reject(err));
155180

156181
return expandedBlocks;
@@ -164,23 +189,13 @@ export class Optimizely {
164189

165190
const { contentBlocks, contentBlocksTop, contentBlocksBottom } = temp;
166191

167-
if (contentBlocks && Array.isArray(contentBlocks) && contentBlocks?.length > 0) {
168-
let expandedContentBlocks = await handleContentBlocks(contentBlocks);
169-
170-
temp.contentBlocks = expandedContentBlocks;
171-
}
192+
let expandedContentBlocks = contentBlocks && Array.isArray(contentBlocks) && contentBlocks?.length > 0 ? await handleContentBlocks(contentBlocks) : null;
193+
let expandedContentBlocksTop = contentBlocksTop && Array.isArray(contentBlocksTop) && contentBlocksTop?.length > 0 ? await handleContentBlocks(contentBlocksTop) : null;
194+
let expandedContentBlocksBottom = contentBlocksBottom && Array.isArray(contentBlocksBottom) && contentBlocksBottom?.length > 0 ? await handleContentBlocks(contentBlocksBottom) : null;
172195

173-
if (contentBlocksTop && Array.isArray(contentBlocksTop) && contentBlocksTop?.length > 0) {
174-
let expandedContentBlocksTop = await handleContentBlocks(contentBlocksTop);
175-
176-
temp.contentBlocksTop = expandedContentBlocksTop;
177-
}
178-
179-
if (contentBlocksBottom && Array.isArray(contentBlocksBottom) && contentBlocksBottom?.length > 0) {
180-
let expandedContentBlocksBottom = await handleContentBlocks(contentBlocksBottom);
181-
182-
temp.contentBlocksBottom = expandedContentBlocksBottom;
183-
}
196+
temp.contentBlocks = expandedContentBlocks;
197+
temp.contentBlocksTop = expandedContentBlocksTop;
198+
temp.contentBlocksBottom = expandedContentBlocksBottom;
184199

185200
return temp;
186201
})
@@ -190,37 +205,19 @@ export class Optimizely {
190205

191206
return expandedResponse;
192207
} else if (response && Object.prototype.toString.call(response) === "[object Object]" && Object.keys(response)?.length > 0) {
193-
try {
194-
const expandedResponsePromise = new Promise((resolve, reject) => {
195-
const temp = Object.assign({}, response);
208+
const temp = Object.assign({}, response);
196209

197-
const { contentBlocks = null, contentBlocksTop = null, contentBlocksBottom = null } = temp;
210+
const { contentBlocks = null, contentBlocksTop = null, contentBlocksBottom = null } = temp;
198211

199-
if (contentBlocks && Array.isArray(contentBlocks) && contentBlocks?.length > 0) {
200-
let expandedContentBlocks = handleContentBlocks(contentBlocks);
212+
let expandedContentBlocks = contentBlocks && Array.isArray(contentBlocks) && contentBlocks?.length > 0 ? await handleContentBlocks(contentBlocks) : null;
213+
let expandedContentBlocksTop = contentBlocksTop && Array.isArray(contentBlocksTop) && contentBlocksTop?.length > 0 ? await handleContentBlocks(contentBlocksTop) : null;
214+
let expandedContentBlocksBottom = contentBlocksBottom && Array.isArray(contentBlocksBottom) && contentBlocksBottom?.length > 0 ? await handleContentBlocks(contentBlocksBottom) : null;
201215

202-
temp.contentBlocks = expandedContentBlocks;
203-
}
204-
205-
if (contentBlocksTop && Array.isArray(contentBlocksTop) && contentBlocksTop?.length > 0) {
206-
let expandedContentBlocksTop = handleContentBlocks(contentBlocksTop);
207-
208-
temp.contentBlocksTop = expandedContentBlocksTop;
209-
}
210-
211-
if (contentBlocksBottom && Array.isArray(contentBlocksBottom) && contentBlocksBottom?.length > 0) {
212-
let expandedContentBlocksBottom = handleContentBlocks(contentBlocksBottom);
216+
temp.contentBlocks = expandedContentBlocks;
217+
temp.contentBlocksTop = expandedContentBlocksTop;
218+
temp.contentBlocksBottom = expandedContentBlocksBottom;
213219

214-
temp.contentBlocksBottom = expandedContentBlocksBottom;
215-
}
216-
217-
return temp ? resolve(temp) : reject(temp);
218-
});
219-
220-
return expandedResponsePromise;
221-
} catch (err) {
222-
return Promise.reject(err);
223-
}
220+
return temp;
224221
} else return response;
225222
}
226223

0 commit comments

Comments
 (0)