Skip to content

Commit

Permalink
#69 refactor http task with to include new codes
Browse files Browse the repository at this point in the history
  • Loading branch information
florentinvintila committed May 3, 2022
1 parent 51ae472 commit 5a23158
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 66 deletions.
66 changes: 41 additions & 25 deletions commands/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ module.exports = {
* headers [Text Area - new line delimitered list?]
* content type [Select - Options: any, text, xml, json, html]
* body [Text Area - optional depending on method]
* @param {string} errorcodes Represents a list of HTTP Status Codes, used either for error or success checks
* @param {string} isErrorCodes Represents if the `errorcodes` param is used as failure (true) or success (false)
* @param {int} httperrorretry Represents the number of retries that will be perfomed until success is obtained or the number of retries is achived
* @param {int} httpRetryDelay Represents the number of miliseconds that will delay the next retry
* @param {string} successcodes Represents a list of HTTP Status Codes, used for success checks
* @param {string} retrycodes Represents a list of HTTP Status Codes, used for retry checks
* @param {string} errorcodes Represents a list of HTTP Status Codes, used for error checks
* @param {int} retrynumber Represents the number of retries that will be perfomed until success is obtained or the number of retries is achived
* @param {int} retrydelay Represents the number of miliseconds that will delay the next retry
* Allow untrusted SSL certs [Boolean Toggle]
*/
execute() {
Expand All @@ -25,38 +26,52 @@ module.exports = {
//Destructure and get properties ready.
const taskProps = utils.resolveInputParameters();

const { url, method, header, contentType, body, allowUntrustedCerts, outputFilePath, errorcodes = "", isErrorCodes = "failure", httperrorretry = 0, httpRetryDelay = 200 } = taskProps;
const { url, method, header, contentType, body, allowUntrustedCerts, outputFilePath, successcodes = "1xx,2xx", retrycodes = "502,503", errorcodes = "", retrynumber = 0, retrydelay = 200 } = taskProps;

// Input force defaults
let newisErrorCodes = "failure";
let newhttperrorretry = 0;
let newhttpRetryDelay = 200;
let newretrynumber = 0;
let newretrydelay = 200;
let newbody = "";
// Input not "empty", set value
if (!checkIfEmpty(isErrorCodes)) {
newisErrorCodes = isErrorCodes.trim().toLowerCase(); // Input normalization
if (!checkIfEmpty(successcodes)) {
newsuccesscodes = successcodes
.toString()
.trim()
.toLowerCase(); // Input normalization
}
if (!checkIfEmpty(httperrorretry)) {
newhttperrorretry = parseInt(httperrorretry, 10);
if (isNaN(newhttperrorretry)) {
log.err("Invalid input for: httperrorretry");
if (!checkIfEmpty(retrycodes)) {
newretrycodes = retrycodes
.toString()
.trim()
.toLowerCase(); // Input normalization
}
if (!checkIfEmpty(errorcodes)) {
newerrorcodes = errorcodes
.toString()
.trim()
.toLowerCase(); // Input normalization
}
if (!checkIfEmpty(retrynumber)) {
newretrynumber = parseInt(retrynumber, 10);
if (isNaN(newretrynumber)) {
log.err("Invalid input for: retrynumber");
process.exit(1);
}
if (newhttperrorretry < 0 || newhttperrorretry > 10) {
log.err("Invalid input for: httperrorretry [0,10]");
if (newretrynumber < 1 || newretrynumber > 9) {
log.err("Invalid input for: retrynumber [1,9]");
process.exit(1);
}
}
if (!checkIfEmpty(httpRetryDelay)) {
newhttpRetryDelay = parseInt(httpRetryDelay, 10);
if (!checkIfEmpty(retrydelay)) {
newretrydelay = parseInt(retrydelay, 10);
// parse test
if (isNaN(newhttpRetryDelay)) {
log.err("Invalid input for: httpRetryDelay");
if (isNaN(newretrydelay)) {
log.err("Invalid input for: retrydelay");
process.exit(1);
}
// bounds exceeded
if (newhttpRetryDelay < 100 || newhttpRetryDelay > 30000) {
log.err("Invalid input for: httpRetryDelay [100,30000]");
if (newretrydelay < 100 || newretrydelay > 300000) {
log.err("Invalid input for: retrydelay [100,300000]");
process.exit(1);
}
}
Expand Down Expand Up @@ -147,10 +162,11 @@ module.exports = {
log.sys("Commencing to execute HTTP call with", reqURL, JSON.stringify(opts));

let config = {
SUCCESS_CODES: successcodes.toString(), // Force string
RETRY_CODES: retrycodes.toString(), // Force string
ERROR_CODES: errorcodes.toString(), // Force string
MAX_RETRIES: newhttperrorretry,
DELAY: newhttpRetryDelay,
IS_ERROR: newisErrorCodes === "failure"
MAX_RETRIES: newretrynumber,
DELAY: newretrydelay
};
if (!checkIfEmpty(newbody)) {
log.debug("writing request body: \n ", newbody);
Expand Down
111 changes: 70 additions & 41 deletions libs/HTTPRetryRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ const utilities = require("./utilities");
const { checkForJson } = require("./../libs/utilities");

let DEFAULTS = {
MAX_RETRIES: 5,
SUCCESS_CODES: "",
RETRY_CODES: "",
ERROR_CODES: "",
MAX_RETRIES: 5,
DELAY: 200,
IS_ERROR: true
};
Expand All @@ -23,6 +25,28 @@ function HTTPRetryRequest(config, URL, options) {
// log.debug("HTTP Request Options:", _self.options);
_self.config = { ...DEFAULTS, ...config }; // overwrite defaults
// log.debug("HTTP Request Config:", _self.config);
if (_self.config.SUCCESS_CODES && _self.config.SUCCESS_CODES.length) {
// create pattern of /(5\d\d|4\d\d|9\d\d)/
// TODO: replace back with replaceAll after node version is above 15.0.0
// _self.config.SUCCESS_CODES = _self.config.SUCCESS_CODES.replaceAll(",", "|"); // replace sperator , with | for regex
_self.config.SUCCESS_CODES = _self.config.SUCCESS_CODES.replace(/\,/g, "|"); // replace sperator , with | for regex
_self.config.SUCCESS_CODES = _self.config.SUCCESS_CODES.toUpperCase(); // make uppercase (x -> X)
// TODO: replace back with replaceAll after node version is above 15.0.0
// _self.config.SUCCESS_CODES = _self.config.SUCCESS_CODES.replaceAll("X", "\\d"); // replace character X with \d for regex - represents a digit
_self.config.SUCCESS_CODES = _self.config.SUCCESS_CODES.replace(/X/g, "\\d"); // replace character X with \d for regex - represents a digit
_self.config.SUCCESS_CODES = new RegExp("(" + _self.config.SUCCESS_CODES + ")"); // wrap in () to have the alternative
}
if (_self.config.RETRY_CODES && _self.config.RETRY_CODES.length) {
// create pattern of /(5\d\d|4\d\d|9\d\d)/
// TODO: replace back with replaceAll after node version is above 15.0.0
// _self.config.RETRY_CODES = _self.config.RETRY_CODES.replaceAll(",", "|"); // replace sperator , with | for regex
_self.config.RETRY_CODES = _self.config.RETRY_CODES.replace(/\,/g, "|"); // replace sperator , with | for regex
_self.config.RETRY_CODES = _self.config.RETRY_CODES.toUpperCase(); // make uppercase (x -> X)
// TODO: replace back with replaceAll after node version is above 15.0.0
// _self.config.RETRY_CODES = _self.config.RETRY_CODES.replaceAll("X", "\\d"); // replace character X with \d for regex - represents a digit
_self.config.RETRY_CODES = _self.config.RETRY_CODES.replace(/X/g, "\\d"); // replace character X with \d for regex - represents a digit
_self.config.RETRY_CODES = new RegExp("(" + _self.config.RETRY_CODES + ")"); // wrap in () to have the alternative
}
if (_self.config.ERROR_CODES && _self.config.ERROR_CODES.length) {
// create pattern of /(5\d\d|4\d\d|9\d\d)/
// TODO: replace back with replaceAll after node version is above 15.0.0
Expand All @@ -48,59 +72,64 @@ function HTTPRetryRequest(config, URL, options) {
.on("error", error => {
log.debug(`Retry onError #${_self.config.retryCount} HTTP Status Code: ${innerStatusCode} \n Status Message: ${response.statusMessage.toString()} \n Response ${_self.buffer.toString()}.`);
responseInstance.abort();
if (_self.config.ERROR_CODES && _self.config.ERROR_CODES.test(innerStatusCode) && _self.config.retryCount <= _self.config.MAX_RETRIES) {
if (!_self.config.IS_ERROR) {
// Success branch and one of the status codes is found, resolve with success
resolve({
statusCode: innerStatusCode,
body: Buffer.alloc(0) // empty body
});
return; // exit to avoid next call
}
if (_self.config.ERROR_CODES && _self.config.ERROR_CODES.test(innerStatusCode)) {
log.debug(`onError - user specific error reject.`);
reject(error);
return;
}
if (_self.config.SUCCESS_CODES && _self.config.SUCCESS_CODES.test(innerStatusCode)) {
// Success branch and one of the status codes is found, resolve with success
resolve({
statusCode: innerStatusCode,
body: Buffer.alloc(0) // empty body
});
return; // exit to avoid next call
}
if (_self.config.RETRY_CODES && _self.config.RETRY_CODES.test(innerStatusCode) && _self.config.retryCount <= _self.config.MAX_RETRIES) {
setTimeout(timeOutRetry, _self.config.DELAY, _self.config, _self.URL, _self.options, resolve);
// TODO: replace after node version is above 15.0.0
// log.debug(`Retry onError #${_self.config.retryCount} next call.`);
// resolve(setTimeoutPromise(_self.config.DELAY, new HTTPRetryRequest( _self.config, _self.URL, _self.options)));
} else {
log.debug(`onError #${_self.config.retryCount} reject.`);
// no more tries, just reject
reject(error);
return;
}
log.debug(`onError - other error reject.`);
reject(error);
})
.on("data", chunk => (_self.buffer = Buffer.concat([_self.buffer, chunk])))
.on("end", () => {
log.debug(`Retry onEnd #${_self.config.retryCount} HTTP Status Code: ${innerStatusCode} \n Status Message: ${response.statusMessage.toString()} \n Response ${_self.buffer.toString()}.`);
if (_self.config.ERROR_CODES && _self.config.ERROR_CODES.test(innerStatusCode) && _self.config.retryCount <= _self.config.MAX_RETRIES) {
if (!_self.config.IS_ERROR) {
// Success branch and one of the status codes is found, resolve with success
resolve({
statusCode: innerStatusCode,
body: _self.buffer
});
return; // exit to avoid next call
}
if (_self.config.ERROR_CODES && _self.config.ERROR_CODES.test(innerStatusCode)) {
log.debug(`onEnd - user specific error reject.\n StatusMessage: ${response.statusMessage.toString()} \n Response ${_self.buffer.toString()}.`);
reject({
statusCode: innerStatusCode,
statusMessage: response.statusMessage,
body: _self.buffer
});
}
if (_self.config.SUCCESS_CODES && (_self.config.SUCCESS_CODES.test(innerStatusCode) || /2\d\d/g.test(innerStatusCode.toString()))) {
log.debug(`onEnd #${_self.config.retryCount} resolve.`);
// Success branch and one of the status codes is found, resolve with success
resolve({
statusCode: innerStatusCode,
body: _self.buffer
});
return; // exit to avoid next call
}
if (_self.config.RETRY_CODES && _self.config.RETRY_CODES.test(innerStatusCode) && _self.config.retryCount <= _self.config.MAX_RETRIES) {
setTimeout(timeOutRetry, _self.config.DELAY, _self.config, _self.URL, _self.options, resolve);
// TODO: replace after node version is above 15.0.0
// log.debug(`Retry onEnd #${_self.config.retryCount} next call.`);
// log.debug(`Retry onError #${_self.config.retryCount} next call.`);
// resolve(setTimeoutPromise(_self.config.DELAY, new HTTPRetryRequest( _self.config, _self.URL, _self.options)));
} else {
log.debug(`onEnd #${_self.config.retryCount} resolve.`);
if (/2\d\d/g.test(innerStatusCode.toString())) {
resolve({
statusCode: innerStatusCode,
body: _self.buffer
});
} else {
// no more tries, just reject
log.debug(`onEnd reject \n StatusMessage: ${response.statusMessage.toString()} \n Response ${_self.buffer.toString()}.`);
// reject(new Error(innerStatusCode, { cause: `StatusMessage: ${response.statusMessage.toString()} \n Response ${_self.buffer.toString()}.`}));
reject({
statusCode: innerStatusCode,
statusMessage: response.statusMessage,
body: _self.buffer
});
}
return;
}
// no more tries, just reject
log.debug(`onEnd reject \n StatusMessage: ${response.statusMessage.toString()} \n Response ${_self.buffer.toString()}.`);
// reject(new Error(innerStatusCode, { cause: `StatusMessage: ${response.statusMessage.toString()} \n Response ${_self.buffer.toString()}.`}));
reject({
statusCode: innerStatusCode,
statusMessage: response.statusMessage,
body: _self.buffer
});
});
});
requestInstance.on("error", err => {
Expand Down

0 comments on commit 5a23158

Please sign in to comment.