Skip to content

Commit 370db2d

Browse files
committed
Changes for retrying in case of network issue
1 parent 8b75f38 commit 370db2d

File tree

6 files changed

+103
-14
lines changed

6 files changed

+103
-14
lines changed

bin/commands/runs.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ const archiver = require("../helpers/archiver"),
88
Constants = require("../helpers/constants"),
99
utils = require("../helpers/utils"),
1010
fileHelpers = require("../helpers/fileHelpers"),
11-
syncRunner = require("../helpers/syncRunner"),
12-
syncCliLogger = require("../helpers/logger").syncCliLogger;
11+
syncRunner = require("../helpers/syncRunner");
1312

1413
module.exports = function run(args) {
1514
let bsConfigPath = utils.getConfigPath(args.cf);
@@ -73,9 +72,7 @@ module.exports = function run(args) {
7372
if (args.sync) {
7473
syncRunner.pollBuildStatus(bsConfig, data).then((exitCode) => {
7574
utils.sendUsageReport(bsConfig, args, `${message}\n${dashboardLink}`, Constants.messageTypes.SUCCESS, null);
76-
syncCliLogger.info(Constants.userMessages.BUILD_REPORT_MESSAGE);
77-
syncCliLogger.info(data.dashboard_url);
78-
process.exit(exitCode);
75+
utils.handleSyncExit(exitCode, data.dashboard_url)
7976
});
8077
}
8178

bin/helpers/config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@ config.cypress_v1 = `${config.rails_host}/automate/cypress/v1`;
1616
config.buildUrl = `${config.cypress_v1}/builds/`;
1717
config.buildStopUrl = `${config.cypress_v1}/builds/stop/`;
1818
config.fileName = "tests.zip";
19+
config.retries = 5;
20+
config.networkErrorExitCode = 2;
1921

2022
module.exports = config;

bin/helpers/sync/failedSpecsDetails.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ const tablePrinter = require('table'), // { table, getBorderCharacters }
1919
//
2020
let failedSpecsDetails = (data) => {
2121
return new Promise((resolve, reject) => {
22-
data.exitCode = 0;
22+
if (!data.exitCode) data.exitCode = 0;
23+
2324
if (data.specs.length === 0) resolve(data); // return if no failed/skipped tests.
2425

2526
let failedSpecs = false;
@@ -72,7 +73,7 @@ let failedSpecsDetails = (data) => {
7273
logger.info('\nFailed / skipped test report:');
7374
logger.info(result);
7475

75-
if (failedSpecs) data.exitCode = 1 ; // specs failed, send exitCode as 1
76+
if (failedSpecs && data.exitCode !== 2) data.exitCode = 1 ; // specs failed, send exitCode as 1
7677
resolve(data); // No Specs failed, maybe skipped, but not failed, send exitCode as 0
7778
});
7879
}

bin/helpers/sync/syncSpecsLogs.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const request = require("request"),
88
tableStream = require('table').createStream,
99
chalk = require('chalk');
1010

11-
let whileLoop = true, whileTries = 40, options, timeout = 3000, n = 10, tableConfig, stream, startTime, endTime;
11+
let whileLoop = true, whileTries = config.retries, options, timeout = 3000, n = 10, tableConfig, stream, endTime, startTime = Date.now();
1212
let specSummary = {
1313
"specs": [],
1414
"duration": null
@@ -22,6 +22,7 @@ let getOptions = (auth, build_id) => {
2222
user: auth.username,
2323
password: auth.access_key
2424
},
25+
timeout: 10000,
2526
headers: {
2627
"Content-Type": "application/json",
2728
"User-Agent": utils.getUserAgent()
@@ -80,6 +81,7 @@ let printSpecsStatus = (bsConfig, buildDetails) => {
8081
whileProcess(callback)
8182
},
8283
function(err, result) { // when loop ends
84+
logger.info("\n--------------------------------------------------------------------------------")
8385
specSummary.duration = endTime - startTime
8486
resolve(specSummary)
8587
}
@@ -90,8 +92,24 @@ let printSpecsStatus = (bsConfig, buildDetails) => {
9092
let whileProcess = (whilstCallback) => {
9193
request.post(options, function(error, response, body) {
9294
if (error) {
93-
return whilstCallback(error);
95+
if (error.code === "ETIMEDOUT") {
96+
whileTries -= 1;
97+
if (whileTries === 0) {
98+
whileLoop = false;
99+
endTime = Date.now();
100+
specSummary.exitCode = config.networkErrorExitCode;
101+
return whilstCallback({ status: 504, message: "Tries limit reached" }); //Gateway Timeout
102+
} else {
103+
n = 2
104+
return setTimeout(whilstCallback, timeout * n, null);
105+
}
106+
} else {
107+
return whilstCallback(error);
108+
}
94109
}
110+
111+
whileTries = config.retries; // reset to default after every successful request
112+
95113
switch (response.statusCode) {
96114
case 202: // get data here and print it
97115
n = 2
@@ -104,7 +122,6 @@ let whileProcess = (whilstCallback) => {
104122
whileLoop = false;
105123
endTime = Date.now();
106124
showSpecsStatus(body);
107-
logger.info("\n--------------------------------------------------------------------------------")
108125
return whilstCallback(null, body);
109126
default:
110127
whileLoop = false;
@@ -125,7 +142,6 @@ let showSpecsStatus = (data) => {
125142
}
126143

127144
let printInitialLog = () => {
128-
startTime = Date.now();
129145
logger.info(`\n${Constants.syncCLI.LOGS.INIT_LOG}`)
130146
logger.info("--------------------------------------------------------------------------------")
131147
n = Constants.syncCLI.INITIAL_DELAY_MULTIPLIER

bin/helpers/utils.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ const fs = require("fs");
55

66
const usageReporting = require("./usageReporting"),
77
logger = require("./logger").winstonLogger,
8-
Constants = require("./constants");
8+
Constants = require("./constants"),
9+
chalk = require('chalk'),
10+
syncCliLogger = require("../helpers/logger").syncCliLogger,
11+
config = require("../helpers/config");
912

1013
exports.validateBstackJson = (bsConfigPath) => {
1114
return new Promise(function (resolve, reject) {
@@ -318,3 +321,20 @@ exports.setLocalIdentifier = (bsConfig) => {
318321
exports.capitalizeFirstLetter = (stringToCapitalize) => {
319322
return stringToCapitalize && (stringToCapitalize[0].toUpperCase() + stringToCapitalize.slice(1));
320323
};
324+
325+
exports.handleSyncExit = (exitCode, dashboard_url) => {
326+
if (exitCode === config.networkErrorExitCode) {
327+
syncCliLogger.info(this.getNetworkErrorMessage(dashboard_url));
328+
} else {
329+
syncCliLogger.info(Constants.userMessages.BUILD_REPORT_MESSAGE);
330+
syncCliLogger.info(dashboard_url);
331+
}
332+
process.exit(exitCode);
333+
}
334+
335+
exports.getNetworkErrorMessage = (dashboard_url) => {
336+
let message = `fatal: unable to access '${config.buildUrl}': Could not resolve host: ${config.rails_host}` + '\n'
337+
+ `Max retries exceeded trying to connect to the host (retries: ${config.retries})` + '\n'
338+
+ `Please check the build status at: ${dashboard_url}`
339+
return chalk.red(message)
340+
}

test/unit/bin/helpers/sync/syncSpecsLogs.js

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ describe("syncSpecsLogs", () => {
9696
expect(options.columns[1].alignment).to.equal('center');
9797
expect(options.columns[2].alignment).to.equal('left');
9898
expect(options.columns[1].width).to.equal(1);
99-
expect(options.columns[2].width).to.equal(30);
99+
expect(options.columns[2].width).to.equal(50);
100100
expect(options.columnCount).to.equal(3);
101101
expect(getBorderConfigStub.calledOnce).to.be.true;
102102
});
@@ -259,7 +259,60 @@ describe("syncSpecsLogs", () => {
259259
context("whileProcess", () => {
260260
const whileProcess = syncSpecsLogs.__get__("whileProcess");
261261

262-
it('Should break the loop if request has error', () => {
262+
context('network issue', () => {
263+
it('Should retry when error is because of network issue', () => {
264+
let delayed_n = 2, timeout = 3000, n = 1;
265+
let error = new Error("error");
266+
error.code = "ETIMEDOUT";
267+
268+
let requestStub = sandbox.stub();
269+
270+
let postStub = sandbox
271+
.stub(request, "post")
272+
.yields(error, { statusCode: 502 }, JSON.stringify({}));
273+
274+
requestStub.post = postStub;
275+
276+
let setTimeout = sandbox.stub();
277+
syncSpecsLogs.__set__('setTimeout', setTimeout);
278+
syncSpecsLogs.__set__('n', n);
279+
syncSpecsLogs.__set__('timeout', timeout);
280+
syncSpecsLogs.__set__('request', requestStub);
281+
syncSpecsLogs.__set__('whileTries', 5);
282+
283+
let whilstCallback = sandbox.stub();
284+
whileProcess(whilstCallback);
285+
286+
sinon.assert.calledWith(setTimeout, whilstCallback, timeout * delayed_n, null);
287+
expect(syncSpecsLogs.__get__("whileTries")).to.equal(4);
288+
});
289+
290+
it('Should give-up on retry when error is b because of network issue after 5 retries and set proper exit code', () => {
291+
let error = new Error("error"), requestStub = sandbox.stub();
292+
error.code = "ETIMEDOUT";
293+
294+
let postStub = sandbox
295+
.stub(request, "post")
296+
.yields(error, { statusCode: 502 }, JSON.stringify({}));
297+
298+
requestStub.post = postStub;
299+
300+
syncSpecsLogs.__set__('request', requestStub);
301+
syncSpecsLogs.__set__('whileTries', 1);
302+
syncSpecsLogs.__set__('specSummary', {});
303+
syncSpecsLogs.__set__('whileLoop', true);
304+
305+
let whilstCallback = sandbox.stub();
306+
whileProcess(whilstCallback);
307+
308+
sinon.assert.calledWith(whilstCallback, { status: 504, message: "Tries limit reached" });
309+
expect(syncSpecsLogs.__get__("whileTries")).to.equal(0);
310+
expect(syncSpecsLogs.__get__("whileLoop")).to.equal(false);
311+
expect(syncSpecsLogs.__get__("specSummary.exitCode")).to.equal(2);
312+
});
313+
});
314+
315+
it('Should break the loop if request has error other than network issue', () => {
263316
let error = new Error("error");
264317
let requestStub = sandbox.stub();
265318
let postStub = sandbox

0 commit comments

Comments
 (0)