Skip to content

Commit c978555

Browse files
committed
fix: retry api requests on rate limit or persistent connection errors
1 parent 58e380b commit c978555

File tree

1 file changed

+84
-53
lines changed

1 file changed

+84
-53
lines changed

lib/Api.js

Lines changed: 84 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,24 @@ let baseUri
1313
let port
1414

1515
function requestEnd (res, rawData, errorCallback, successCallback) {
16+
let str, err
1617
switch (res.statusCode) {
1718
case 200:
1819
case 201:
1920
case 204:
2021
successCallback()
2122
break
22-
2323
case 412:
2424
// no store found with provided ID
2525
errorCallback(null, 412, 'Invalid store ID')
2626
break
27-
2827
default:
2928
// unexpected status code
30-
let str = 'Unexpected response status code from Store API' +
29+
str = 'Unexpected response status code from Store API' +
3130
'\nStatus: ' + res.statusCode +
3231
'\nResponse: ' + rawData
33-
let err = new Error(str)
32+
err = new Error(str)
33+
err.statusCode = res.statusCode
3434
errorCallback(err)
3535
}
3636
}
@@ -48,8 +48,57 @@ require('./../lib/Config.js')((config) => {
4848
port = config.apiPort
4949
})
5050

51-
module.exports = (endpoint, method, body, storeId, errorCallback, successCallback, publicApi = false) => {
52-
let options = {
51+
const request = (
52+
client,
53+
options,
54+
body,
55+
errorCallback,
56+
successCallback
57+
) => {
58+
const req = client.request(options, (res) => {
59+
let rawData = ''
60+
res.setEncoding('utf8')
61+
res.on('data', (chunk) => { rawData += chunk })
62+
res.on('end', () => {
63+
requestEnd(res, rawData, errorCallback, () => {
64+
// OK
65+
let parsedData
66+
if (rawData) {
67+
try {
68+
parsedData = JSON.parse(rawData)
69+
} catch (e) {
70+
// not a valid JSON
71+
// callback without response body
72+
errorCallback(e)
73+
return
74+
}
75+
}
76+
if (typeof successCallback === 'function') {
77+
// pass parsed JSON
78+
successCallback(parsedData)
79+
}
80+
})
81+
})
82+
})
83+
req.on('error', errorCallback)
84+
if (body) {
85+
// write data to request body
86+
req.write(JSON.stringify(body))
87+
}
88+
req.end()
89+
}
90+
91+
module.exports = (
92+
endpoint,
93+
method,
94+
body,
95+
storeId,
96+
errorCallback,
97+
successCallback,
98+
publicApi = false,
99+
canRetry = true
100+
) => {
101+
const options = {
53102
hostname: !publicApi ? host : 'api.e-com.plus',
54103
path: baseUri + endpoint,
55104
method: method,
@@ -60,53 +109,35 @@ module.exports = (endpoint, method, body, storeId, errorCallback, successCallbac
60109
if (!publicApi && port) {
61110
options.port = port
62111
}
112+
const client = !publicApi ? http : https
63113

64-
let client = !publicApi ? http : https
65-
let req = client.request(options, (res) => {
66-
if (typeof errorCallback === 'function') {
67-
let rawData = ''
68-
res.setEncoding('utf8')
69-
res.on('data', (chunk) => { rawData += chunk })
70-
res.on('end', () => {
71-
requestEnd(res, rawData, errorCallback, () => {
72-
// OK
73-
let parsedData
74-
if (rawData) {
75-
try {
76-
parsedData = JSON.parse(rawData)
77-
} catch (e) {
78-
// not a valid JSON
79-
// callback without response body
80-
errorCallback(e)
81-
return
82-
}
83-
}
84-
85-
if (typeof successCallback === 'function') {
86-
// pass parsed JSON
87-
successCallback(parsedData)
88-
}
89-
})
90-
})
91-
} else {
92-
// consume response data to free up memory
93-
res.resume()
94-
}
95-
})
96-
97-
req.on('error', (e) => {
98-
if (typeof errorCallback === 'function') {
99-
errorCallback(e)
100-
} else {
101-
// no callback
102-
// just log the unexpected error
103-
logger.error(e)
104-
}
105-
})
106-
107-
if (body) {
108-
// write data to request body
109-
req.write(JSON.stringify(body))
114+
let retries = 0
115+
const maxRetries = canRetry
116+
? endpoint.startsWith('orders') ? 2 : 1
117+
: 0
118+
const requestWithRetry = () => {
119+
request(
120+
client,
121+
options,
122+
body,
123+
(err) => {
124+
if (err instanceof Error && !(err.statusCode < 500) && retries < maxRetries) {
125+
retries++
126+
setTimeout(() => {
127+
requestWithRetry()
128+
}, retries * (publicApi ? 600 : 1000))
129+
return
130+
}
131+
if (typeof errorCallback === 'function') {
132+
errorCallback(err)
133+
} else {
134+
// no callback
135+
// just log the unexpected error
136+
logger.error(err)
137+
}
138+
},
139+
successCallback
140+
)
110141
}
111-
req.end()
142+
requestWithRetry()
112143
}

0 commit comments

Comments
 (0)