fix: guard async onTrace callbacks against unhandled rejection
Detect when onTrace returns a Promise and .catch() the rejection, preventing unhandled promise rejection from crashing the process. Addresses Codex review feedback on PR #40.
This commit is contained in:
parent
a49b24c22a
commit
8f7fc2019b
|
|
@ -15,12 +15,19 @@ export function emitTrace(
|
|||
): void {
|
||||
if (!fn) return
|
||||
try {
|
||||
fn(event)
|
||||
// Guard async callbacks: if fn returns a Promise, swallow its rejection
|
||||
// so an async onTrace never produces an unhandled promise rejection.
|
||||
const result = fn(event) as unknown
|
||||
if (result && typeof (result as Promise<unknown>).catch === 'function') {
|
||||
;(result as Promise<unknown>).catch(noop)
|
||||
}
|
||||
} catch {
|
||||
// Intentionally swallowed — observability must never break execution.
|
||||
}
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
|
||||
/** Generate a unique run ID for trace correlation. */
|
||||
export function generateRunId(): string {
|
||||
return randomUUID()
|
||||
|
|
|
|||
|
|
@ -136,6 +136,25 @@ describe('emitTrace', () => {
|
|||
}),
|
||||
).not.toThrow()
|
||||
})
|
||||
|
||||
it('swallows rejected promises from async callbacks', async () => {
|
||||
// An async onTrace that rejects should not produce unhandled rejection
|
||||
const fn = async () => { throw new Error('async boom') }
|
||||
emitTrace(fn as unknown as (event: TraceEvent) => void, {
|
||||
type: 'agent',
|
||||
runId: 'r1',
|
||||
agent: 'a',
|
||||
turns: 1,
|
||||
tokens: { input_tokens: 0, output_tokens: 0 },
|
||||
toolCalls: 0,
|
||||
startMs: 0,
|
||||
endMs: 0,
|
||||
durationMs: 0,
|
||||
})
|
||||
// If the rejection is not caught, vitest will fail with unhandled rejection.
|
||||
// Give the microtask queue a tick to surface any unhandled rejection.
|
||||
await new Promise(resolve => setTimeout(resolve, 10))
|
||||
})
|
||||
})
|
||||
|
||||
describe('generateRunId', () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue