From cc99d4a3b2475672744f69d1915eb3743bd3b5c5 Mon Sep 17 00:00:00 2001 From: ehmicky Date: Sun, 19 May 2024 16:06:11 +0100 Subject: [PATCH] Handle exceptions from the `filter` option of `getOneMessage()` --- lib/ipc/get-one.js | 5 ++++- test/fixtures/ipc-get-filter-throw.js | 9 +++++++++ test/fixtures/ipc-send-get.js | 8 ++++++++ test/ipc/get-one.js | 29 +++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100755 test/fixtures/ipc-get-filter-throw.js create mode 100755 test/fixtures/ipc-send-get.js diff --git a/lib/ipc/get-one.js b/lib/ipc/get-one.js index d58ea2423b..9d00a32113 100644 --- a/lib/ipc/get-one.js +++ b/lib/ipc/get-one.js @@ -1,5 +1,5 @@ import {once, on} from 'node:events'; -import {validateIpcMethod, throwOnEarlyDisconnect} from './validation.js'; +import {validateIpcMethod, throwOnEarlyDisconnect, disconnect} from './validation.js'; import {getIpcEmitter, isConnected} from './forward.js'; import {addReference, removeReference} from './reference.js'; @@ -24,6 +24,9 @@ const getOneMessageAsync = async (anyProcess, isSubprocess, filter) => { getMessage(ipcEmitter, filter, controller), throwOnDisconnect(ipcEmitter, isSubprocess, controller), ]); + } catch (error) { + disconnect(anyProcess); + throw error; } finally { controller.abort(); removeReference(anyProcess); diff --git a/test/fixtures/ipc-get-filter-throw.js b/test/fixtures/ipc-get-filter-throw.js new file mode 100755 index 0000000000..4798e0a863 --- /dev/null +++ b/test/fixtures/ipc-get-filter-throw.js @@ -0,0 +1,9 @@ +#!/usr/bin/env node +import {getOneMessage} from '../../index.js'; +import {foobarString} from '../helpers/input.js'; + +await getOneMessage({ + filter() { + throw new Error(foobarString); + }, +}); diff --git a/test/fixtures/ipc-send-get.js b/test/fixtures/ipc-send-get.js new file mode 100755 index 0000000000..f5eb2afd4a --- /dev/null +++ b/test/fixtures/ipc-send-get.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node +import {sendMessage, getOneMessage} from '../../index.js'; +import {foobarString} from '../helpers/input.js'; + +await Promise.all([ + getOneMessage(), + sendMessage(foobarString), +]); diff --git a/test/ipc/get-one.js b/test/ipc/get-one.js index 4ee43e0758..fd809a5c0d 100644 --- a/test/ipc/get-one.js +++ b/test/ipc/get-one.js @@ -57,6 +57,35 @@ test('exports.getOneMessage() can filter messages', async t => { t.deepEqual(ipcOutput, [foobarArray[1]]); }); +test('Throwing from subprocess.getOneMessage() filter disconnects', async t => { + const subprocess = execa('ipc-send-get.js', {ipc: true}); + const error = new Error(foobarString); + t.is(await t.throwsAsync(subprocess.getOneMessage({ + filter() { + throw error; + }, + })), error); + + const {exitCode, isTerminated, message, ipcOutput} = await t.throwsAsync(subprocess); + t.is(exitCode, 1); + t.false(isTerminated); + t.true(message.includes('Error: getOneMessage() could not complete')); + t.deepEqual(ipcOutput, [foobarString]); +}); + +test('Throwing from exports.getOneMessage() filter disconnects', async t => { + const subprocess = execa('ipc-get-filter-throw.js', {ipc: true, ipcInput: 0}); + await t.throwsAsync(subprocess.getOneMessage(), { + message: /subprocess.getOneMessage\(\) could not complete/, + }); + + const {exitCode, isTerminated, message, ipcOutput} = await t.throwsAsync(subprocess); + t.is(exitCode, 1); + t.false(isTerminated); + t.true(message.includes(`Error: ${foobarString}`)); + t.deepEqual(ipcOutput, []); +}); + test.serial('Can retrieve initial IPC messages under heavy load', async t => { await Promise.all( Array.from({length: PARALLEL_COUNT}, async (_, index) => {