From f2c6bdd9114a8d5ba8473cc647ef55a6ee5664e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iiro=20J=C3=A4ppinen?= Date: Wed, 8 Jun 2022 14:48:16 +0300 Subject: [PATCH] fix: suppress error from `process.kill` when killing tasks on failure --- lib/resolveTaskFn.js | 8 +++++-- test/resolveTaskFn.spec.js | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/lib/resolveTaskFn.js b/lib/resolveTaskFn.js index d62ab7395..7b83a008d 100644 --- a/lib/resolveTaskFn.js +++ b/lib/resolveTaskFn.js @@ -54,12 +54,16 @@ const killExecaProcess = async (execaProcess) => { try { const childPids = await pidTree(execaProcess.pid) for (const childPid of childPids) { - process.kill(childPid) + try { + process.kill(childPid) + } catch (error) { + debugLog(`Failed to kill process with pid "%d": %o`, childPid, error) + } } } catch (error) { // Suppress "No matching pid found" error. This probably means // the process already died before executing. - debugLog(`Failed to find process for pid %d`, execaProcess.pid) + debugLog(`Failed to kill process with pid "%d": %o`, execaProcess.pid, error) } // The execa process is killed separately in order to get the `KILLED` status. diff --git a/test/resolveTaskFn.spec.js b/test/resolveTaskFn.spec.js index b6e79e1ab..cbcf93ba1 100644 --- a/test/resolveTaskFn.spec.js +++ b/test/resolveTaskFn.spec.js @@ -484,4 +484,51 @@ describe('resolveTaskFn', () => { value: realKill, }) }) + + it('should ignore error when trying to kill child processes', async () => { + expect.assertions(3) + + execa.mockImplementationOnce(() => + createExecaReturnValue( + { + stdout: 'a-ok', + stderr: '', + code: 0, + cmd: 'mock cmd', + failed: false, + killed: false, + signal: null, + }, + 1000 + ) + ) + + const realKill = process.kill + const mockKill = jest.fn(() => { + throw new Error('kill ESRCH') + }) + Object.defineProperty(process, 'kill', { + value: mockKill, + }) + + pidTree.mockImplementationOnce(() => ['1234']) + + const taskFn = resolveTaskFn({ command: 'node' }) + + const context = getInitialState() + const taskPromise = taskFn(context) + + context.events.emit('lint-staged:taskError') + + jest.runAllTimers() + + await expect(taskPromise).rejects.toThrowErrorMatchingInlineSnapshot(`"node [KILLED]"`) + + expect(mockKill).toHaveBeenCalledTimes(1) + expect(mockKill).toHaveBeenCalledWith('1234') + + Object.defineProperty(process, 'kill', { + value: realKill, + }) + }) })