Skip to content

Commit 6de5ef3

Browse files
authored
fix: non-async signal handlers with try/finally and fixed test types
1 parent 55a7dbf commit 6de5ef3

2 files changed

Lines changed: 36 additions & 23 deletions

File tree

src/commands/signal-handler.test.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { registerSignalHandlers, SignalHandlerDependencies } from './signal-handler';
22

3+
const flushPromises = (): Promise<void> => new Promise(resolve => setImmediate(resolve));
4+
35
describe('registerSignalHandlers', () => {
46
let processOnSpy: jest.SpyInstance;
57
let processExitSpy: jest.SpyInstance;
68
let consoleErrorSpy: jest.SpyInstance;
7-
const handlers: Record<string, (...args: unknown[]) => void> = {};
9+
const handlers: Record<string, (...args: unknown[]) => unknown> = {};
810

911
beforeEach(() => {
1012
jest.clearAllMocks();
@@ -15,9 +17,7 @@ describe('registerSignalHandlers', () => {
1517
return process;
1618
}
1719
);
18-
processExitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {
19-
throw new Error('process.exit called');
20-
});
20+
processExitSpy = jest.spyOn(process, 'exit').mockImplementation(() => undefined as never);
2121
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
2222
});
2323

@@ -56,7 +56,8 @@ describe('registerSignalHandlers', () => {
5656

5757
registerSignalHandlers(deps);
5858

59-
await expect(handlers['SIGINT']()).rejects.toThrow('process.exit called');
59+
handlers['SIGINT']();
60+
await flushPromises();
6061
expect(fastKill).toHaveBeenCalled();
6162
expect(performCleanup).toHaveBeenCalledWith('SIGINT');
6263
expect(processExitSpy).toHaveBeenCalledWith(130);
@@ -75,7 +76,8 @@ describe('registerSignalHandlers', () => {
7576

7677
registerSignalHandlers(deps);
7778

78-
await expect(handlers['SIGINT']()).rejects.toThrow('process.exit called');
79+
handlers['SIGINT']();
80+
await flushPromises();
7981
expect(fastKill).not.toHaveBeenCalled();
8082
expect(performCleanup).toHaveBeenCalledWith('SIGINT');
8183
});
@@ -93,7 +95,8 @@ describe('registerSignalHandlers', () => {
9395

9496
registerSignalHandlers(deps);
9597

96-
await expect(handlers['SIGINT']()).rejects.toThrow('process.exit called');
98+
handlers['SIGINT']();
99+
await flushPromises();
97100
expect(fastKill).not.toHaveBeenCalled();
98101
});
99102

@@ -110,7 +113,8 @@ describe('registerSignalHandlers', () => {
110113

111114
registerSignalHandlers(deps);
112115

113-
await expect(handlers['SIGTERM']()).rejects.toThrow('process.exit called');
116+
handlers['SIGTERM']();
117+
await flushPromises();
114118
expect(fastKill).toHaveBeenCalled();
115119
expect(performCleanup).toHaveBeenCalledWith('SIGTERM');
116120
expect(processExitSpy).toHaveBeenCalledWith(143);

src/commands/signal-handler.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,37 @@ export interface SignalHandlerDependencies {
2020
* the full `docker compose down` in `performCleanup` is too slow to finish
2121
* in that window and would leave the container running as an orphan.
2222
*/
23-
/* istanbul ignore next -- signal handlers cannot be unit-tested */
2423
export function registerSignalHandlers({
2524
getContainersStarted,
2625
keepContainers,
2726
fastKillAgentContainer,
2827
performCleanup,
2928
}: SignalHandlerDependencies): void {
30-
process.on('SIGINT', async () => {
31-
if (getContainersStarted() && !keepContainers) {
32-
await fastKillAgentContainer();
33-
}
34-
await performCleanup('SIGINT');
35-
console.error(`Process exiting with code: 130`);
36-
process.exit(130); // Standard exit code for SIGINT
29+
process.on('SIGINT', () => {
30+
(async () => {
31+
try {
32+
if (getContainersStarted() && !keepContainers) {
33+
await fastKillAgentContainer();
34+
}
35+
await performCleanup('SIGINT');
36+
} finally {
37+
console.error(`Process exiting with code: 130`);
38+
process.exit(130); // Standard exit code for SIGINT
39+
}
40+
})().catch(() => undefined);
3741
});
3842

39-
process.on('SIGTERM', async () => {
40-
if (getContainersStarted() && !keepContainers) {
41-
await fastKillAgentContainer();
42-
}
43-
await performCleanup('SIGTERM');
44-
console.error(`Process exiting with code: 143`);
45-
process.exit(143); // Standard exit code for SIGTERM
43+
process.on('SIGTERM', () => {
44+
(async () => {
45+
try {
46+
if (getContainersStarted() && !keepContainers) {
47+
await fastKillAgentContainer();
48+
}
49+
await performCleanup('SIGTERM');
50+
} finally {
51+
console.error(`Process exiting with code: 143`);
52+
process.exit(143); // Standard exit code for SIGTERM
53+
}
54+
})().catch(() => undefined);
4655
});
4756
}

0 commit comments

Comments
 (0)