Skip to content

Commit 807a248

Browse files
Abhi591rohitesh-wingify
authored andcommitted
fix: Retry on failed network calls
1 parent 55f18e6 commit 807a248

File tree

7 files changed

+135
-54
lines changed

7 files changed

+135
-54
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.70.0] - 2024-07-18
9+
### Fix
10+
- Retry on failed network calls
11+
812
## [1.69.0] - 2024-06-06
913
### Fix
1014
- Unsupported URL in React native env

dist/vwo-javascript-sdk.js

Lines changed: 36 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vwo-javascript-sdk.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vwo-javascript-sdk.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/vwo-javascript-sdk.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/utils/HttpHandlerUtil.js

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ const HttpHandlerUtil = {
7171
},
7272

7373
sendPostCall: function(url, postData, queryParams, authToken, callback, customHeaders = {}) {
74+
let retry = 0;
75+
const maxRetries = 5;
76+
const delay = 1000;
7477
postData = JSON.stringify(postData);
75-
customHeaders['Content-Length'] = postData.length;
78+
customHeaders['Content-Length'] = Buffer.byteLength(postData);
7679
const options = {
7780
method: 'POST',
7881
hostname: url.host,
@@ -84,31 +87,63 @@ const HttpHandlerUtil = {
8487
if (authToken) {
8588
options.headers.Authorization = authToken;
8689
} else {
87-
// what should be the user-agent here?
90+
// Set the user-agent here
8891
options.headers['User-Agent'] = Constants.SDK_NAME;
8992
}
9093

9194
if (url.port) {
9295
options.port = url.port;
9396
}
9497

95-
const req = https.request(options, res => {
96-
let rawData = ''; // eslint-disable-line no-unused-vars
97-
res.setEncoding('utf8');
98-
res.on('data', function(chunk) {
99-
rawData += chunk;
100-
});
101-
res.on('end', function() {
102-
callback(null, res, rawData);
98+
const sendRequest = retries => {
99+
const req = https.request(options, res => {
100+
let rawData = '';
101+
res.setEncoding('utf8');
102+
res.on('data', function(chunk) {
103+
rawData += chunk;
104+
});
105+
res.on('end', function() {
106+
if (res.statusCode >= 200 && res.statusCode < 300) {
107+
callback(null, res, rawData);
108+
} else {
109+
if (retries < maxRetries) {
110+
logger.log(
111+
LogLevelEnum.ERROR,
112+
`Retrying request... Attempt ${retries + 1} of ${maxRetries} due to status code: ${res.statusCode}`
113+
);
114+
setTimeout(() => sendRequest(retries + 1), delay * (retries + 1)); // Exponential backoff
115+
} else {
116+
logger.log(
117+
LogLevelEnum.ERROR,
118+
`Request failed after ${maxRetries} attempts with status code: ${res.statusCode}`
119+
);
120+
callback(
121+
new Error(`Request failed after ${maxRetries} attempts with status code: ${res.statusCode}`),
122+
res,
123+
rawData
124+
);
125+
}
126+
}
127+
});
103128
});
104-
});
105129

106-
req.on('error', e => {
107-
callback(e, null);
108-
});
130+
req.on('error', e => {
131+
if (retries < maxRetries) {
132+
logger.log(
133+
LogLevelEnum.ERROR,
134+
`Retrying request due to error... Attempt ${retries + 1} of ${maxRetries}. Error: ${e.message}`
135+
);
136+
setTimeout(() => sendRequest(retries + 1), delay * (retries + 1)); // Exponential backoff
137+
} else {
138+
logger.log(LogLevelEnum.ERROR, `Request failed after ${maxRetries} attempts due to error: ${e.message}`);
139+
callback(e, null);
140+
}
141+
});
109142

110-
req.write(postData);
111-
req.end();
143+
req.write(postData);
144+
req.end();
145+
};
146+
sendRequest(retry);
112147
}
113148
};
114149

lib/utils/XhrUtil.js

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,13 @@ const XhrUtil = {
7575
},
7676

7777
// send request function definition (to allow for retries)
78-
sendRequest: function(xhr, retries, maxRetries, delay, logger, customHeaders, payload, method, url, resolve, reject) {
78+
sendRequest: function(retries, maxRetries, logger, customHeaders, payload, method, url, resolve, reject) {
79+
let delay = 1000 * (retries + 1);
80+
let xhr = new XMLHttpRequest();
81+
82+
// Configure timeout
83+
xhr.timeout = 5000; // Set timeout to 5 seconds (5000 ms)
84+
7985
// onload event
8086
xhr.onload = () => {
8187
// retry if error and less than max retries
@@ -84,40 +90,53 @@ const XhrUtil = {
8490
retries++;
8591

8692
// log retried times
87-
logger.log(LogLevelEnum.ERROR, 'Retrying with Status Code :' + xhr.status);
88-
logger.log(LogLevelEnum.ERROR, 'Retrying with Response :' + xhr.responseText);
93+
logger.log(
94+
LogLevelEnum.ERROR,
95+
`Retrying with Status Code : ${xhr.status}, and Response : ${xhr.responseText}`
96+
);
8997

9098
// call send request again, after delay
9199
setTimeout(() => {
92-
this.sendRequest(
93-
xhr,
94-
retries,
95-
maxRetries,
96-
delay,
97-
logger,
98-
customHeaders,
99-
payload,
100-
method,
101-
url,
102-
resolve,
103-
reject
104-
);
100+
this.sendRequest(retries, maxRetries, logger, customHeaders, payload, method, url, resolve, reject);
105101
}, delay);
106102
} else {
107103
// log errors with status (clean up later)
108-
logger.log(LogLevelEnum.ERROR, 'Request failed with Status Code :' + xhr.status);
109-
logger.log(LogLevelEnum.ERROR, 'Request failed with Response :' + xhr.responseText);
104+
logger.log(
105+
LogLevelEnum.ERROR,
106+
`Request failed with Status Code : ${xhr.status} and Response : ${xhr.responseText}`
107+
);
110108
reject(`Got Error: ${xhr.statusText} and Status Code: ${xhr.status}`);
111109
}
112110
} else {
113111
// resolve the promise if all well
114-
resolve();
112+
resolve(xhr.responseText);
115113
}
116114
};
117115

118116
// onerror event
119117
xhr.onerror = () => {
120-
reject(`Error: ${xhr.statusText}, Status Code: ${xhr.status}`);
118+
if (retries < maxRetries) {
119+
retries++;
120+
logger.log(LogLevelEnum.ERROR, 'Retrying due to network error');
121+
setTimeout(() => {
122+
this.sendRequest(retries, maxRetries, logger, customHeaders, payload, method, url, resolve, reject);
123+
}, delay);
124+
} else {
125+
reject(`Network error: ${xhr.statusText}, Status Code: ${xhr.status}`);
126+
}
127+
};
128+
129+
// ontimeout event
130+
xhr.ontimeout = () => {
131+
if (retries < maxRetries) {
132+
retries++;
133+
logger.log(LogLevelEnum.ERROR, 'Retrying due to timeout');
134+
setTimeout(() => {
135+
this.sendRequest(retries, maxRetries, logger, customHeaders, payload, method, url, resolve, reject);
136+
}, delay);
137+
} else {
138+
reject(`Timeout error: ${xhr.statusText}, Status Code: ${xhr.status}`);
139+
}
121140
};
122141

123142
// open connection and add headers if any, and then send
@@ -154,10 +173,9 @@ const XhrUtil = {
154173
// retry params
155174
let retries = 0;
156175
let maxRetries = 5;
157-
let delay = 1000;
158176

159177
// send request
160-
this.sendRequest(xhr, retries, maxRetries, delay, logger, customHeaders, payload, method, url, resolve, reject);
178+
this.sendRequest(retries, maxRetries, logger, customHeaders, payload, method, url, resolve, reject);
161179
}
162180
},
163181

0 commit comments

Comments
 (0)