From e5c95e2417c92b6bd2d1cd039efe3348ecdb7cd2 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Tue, 7 Jul 2020 10:21:59 -0600 Subject: [PATCH 1/4] Handle python's 120 exit code See https://docs.python.org/3/library/sys.html#sys.exit. This works around issue #339. --- lib/worker.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/worker.js b/lib/worker.js index 2dcdd08b..7683f0a6 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -99,6 +99,9 @@ class Worker { if (results.code === 0) return await this.success(results); if (results.code === 3) return await this.ignore(results); if (results.code === 4) return await this.noop(results); + // Rarely, python may set an exit code of 120 during its cleanup phase. + // We should not retry in this case. + if (results.code === 120) return await this.ignore(results); return await this.fail(results); } catch (err) { clearInterval(heartbeatTimeout); From bed7f06896253dc43c6dd6816613f9909d61ecc3 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Tue, 7 Jul 2020 13:15:16 -0600 Subject: [PATCH 2/4] Add a test for exit code 120 --- test/worker.test.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/worker.test.js b/test/worker.test.js index 07efa16b..d810a060 100644 --- a/test/worker.test.js +++ b/test/worker.test.js @@ -336,6 +336,34 @@ test('[worker] waitFor, exit 4', async (assert) => { assert.end(); }); +test('[worker] waitFor, exit 120', async (assert) => { + const logger = stubber(Logger).setup(); + logger.log.restore(); + logger.stream.restore(); + const message = sinon.createStubInstance(Message); + message.env = { Message: 'forty bananas', SentTimestamp: '2020-11-03T21:57:55.000Z' }; + const options = { command: 'exit 120', volumes: ['/tmp'] }; + const worker = new Worker(message, options); + + sinon.spy(child_process, 'spawn'); + + try { + await worker.waitFor(); + } catch (err) { + assert.ifError(err, 'failed'); + } + + const results = logger.workerFailure.args[0][0]; + assert.equal(results.code, 120, 'logged worker failure exit code'); + assert.ok(results.duration, 'logged worker failure duration'); + assert.ok(results.response_duration, 'logged worker response duration'); + assert.equal(message.complete.callCount, 1, 'calls message.complete()'); + + child_process.spawn.restore(); + logger.teardown(); + assert.end(); +}); + test('[worker] waitFor, child_process.spawn failure', async (assert) => { const logger = stubber(Logger).setup(); logger.log.restore(); From 0d154dc17983381822135f800d6f3081a46c79ef Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Tue, 7 Jul 2020 13:27:58 -0600 Subject: [PATCH 3/4] Use a past timestamp --- test/worker.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/worker.test.js b/test/worker.test.js index d810a060..28677d4f 100644 --- a/test/worker.test.js +++ b/test/worker.test.js @@ -341,7 +341,7 @@ test('[worker] waitFor, exit 120', async (assert) => { logger.log.restore(); logger.stream.restore(); const message = sinon.createStubInstance(Message); - message.env = { Message: 'forty bananas', SentTimestamp: '2020-11-03T21:57:55.000Z' }; + message.env = { Message: 'forty bananas', SentTimestamp: '2019-02-09T21:57:55.000Z' }; const options = { command: 'exit 120', volumes: ['/tmp'] }; const worker = new Worker(message, options); From 3dfcc32e26ad8e8e32be68ab0120b6edd7752bd8 Mon Sep 17 00:00:00 2001 From: Sean Gillies Date: Tue, 7 Jul 2020 13:34:56 -0600 Subject: [PATCH 4/4] Update changelog.md --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index 503f7bd5..cc07a0f8 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,7 @@ +### 4.20.3 + +- Treat a rare python exit code of 120 as a special case of exit code 3 (#340). + ### 4.20.2 - Using InChina instead of NotInChina Cloudformation condition: https://github.com/mapbox/ecs-watchbot/pull/329