Skip to content

Commit 25165df

Browse files
authored
fix(agents-core): process listeners (#45)
* fix process listeners * changeset * add return types
1 parent 6683db0 commit 25165df

File tree

4 files changed

+49
-49
lines changed

4 files changed

+49
-49
lines changed

.changeset/honest-lands-pump.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@openai/agents-core': patch
3+
---
4+
5+
fix: Process hangs on SIGINT because `process.exit` is never called

packages/agents-core/src/index.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import logger from './logger';
21
import { addTraceProcessor } from './tracing';
32
import { defaultProcessor } from './tracing/processor';
4-
import { getGlobalTraceProvider } from './tracing/provider';
53

64
export { RuntimeEventEmitter } from '@openai/agents-core/_shims';
75
export {
@@ -148,25 +146,3 @@ export * as protocol from './types/protocol';
148146
* 2. calling setTraceProcessors, which sets the processors and discards the default one
149147
*/
150148
addTraceProcessor(defaultProcessor());
151-
152-
const cleanup = async () => {
153-
await getGlobalTraceProvider().shutdown();
154-
};
155-
156-
if (typeof process !== 'undefined' && typeof process.on === 'function') {
157-
// handling Node.js process termination
158-
159-
// Handle normal termination
160-
process.on('beforeExit', cleanup);
161-
162-
// Handle CTRL+C (SIGINT)
163-
process.on('SIGINT', cleanup);
164-
165-
// Handle termination (SIGTERM)
166-
process.on('SIGTERM', cleanup);
167-
168-
process.on('unhandledRejection', (reason, promise) => {
169-
logger.error('Unhandled rejection', reason, promise);
170-
cleanup();
171-
});
172-
}

packages/agents-core/src/tracing/index.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import logger from '../logger';
21
import { TracingProcessor } from './processor';
32
import { getGlobalTraceProvider } from './provider';
43

@@ -47,25 +46,3 @@ export function setTraceProcessors(processors: TracingProcessor[]): void {
4746
export function setTracingDisabled(disabled: boolean): void {
4847
getGlobalTraceProvider().setDisabled(disabled);
4948
}
50-
51-
const cleanup = async () => {
52-
await getGlobalTraceProvider().shutdown();
53-
};
54-
55-
if (typeof process !== 'undefined' && typeof process.on === 'function') {
56-
// handling Node.js process termination
57-
58-
// Handle normal termination
59-
process.on('beforeExit', cleanup);
60-
61-
// Handle CTRL+C (SIGINT)
62-
process.on('SIGINT', cleanup);
63-
64-
// Handle termination (SIGTERM)
65-
process.on('SIGTERM', cleanup);
66-
67-
process.on('unhandledRejection', (reason, promise) => {
68-
logger.error('Unhandled rejection', reason, promise);
69-
cleanup();
70-
});
71-
}

packages/agents-core/src/tracing/provider.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export class TraceProvider {
2323
// disable tracing in tests by default
2424
this.#disabled = true;
2525
}
26+
27+
this.#addCleanupListeners();
2628
}
2729

2830
/**
@@ -155,14 +157,54 @@ export class TraceProvider {
155157
);
156158
}
157159

158-
shutdown(timeout?: number): void {
160+
async shutdown(timeout?: number): Promise<void> {
159161
try {
160162
logger.debug('Shutting down tracing provider');
161-
this.#multiProcessor.shutdown(timeout);
163+
await this.#multiProcessor.shutdown(timeout);
162164
} catch (error) {
163165
logger.error('Error shutting down tracing provider %o', error);
164166
}
165167
}
168+
169+
/** Adds listeners to `process` to ensure `shutdown` occurs before exit. */
170+
#addCleanupListeners(): void {
171+
if (typeof process !== 'undefined' && typeof process.on === 'function') {
172+
// handling Node.js process termination
173+
const cleanup = async () => {
174+
const timeout = setTimeout(() => {
175+
console.warn('Cleanup timeout, forcing exit');
176+
process.exit(1);
177+
}, 5000);
178+
179+
try {
180+
await this.shutdown();
181+
} finally {
182+
clearTimeout(timeout);
183+
}
184+
};
185+
186+
// Handle normal termination
187+
process.on('beforeExit', cleanup);
188+
189+
// Handle CTRL+C (SIGINT)
190+
process.on('SIGINT', async () => {
191+
await cleanup();
192+
process.exit(130);
193+
});
194+
195+
// Handle termination (SIGTERM)
196+
process.on('SIGTERM', async () => {
197+
await cleanup();
198+
process.exit(0);
199+
});
200+
201+
process.on('unhandledRejection', async (reason, promise) => {
202+
logger.error('Unhandled rejection', reason, promise);
203+
await cleanup();
204+
process.exit(1);
205+
});
206+
}
207+
}
166208
}
167209

168210
let GLOBAL_TRACE_PROVIDER: TraceProvider | undefined = undefined;

0 commit comments

Comments
 (0)