Skip to content

Commit 537982f

Browse files
authored
Merge pull request #77 from browser-use/alex/v4-shutdown-hook-diagnostics
diag(TEMP): stderr trace through plugin shutdown + forceFlush
2 parents 351e645 + ae8be3e commit 537982f

2 files changed

Lines changed: 38 additions & 4 deletions

File tree

packages/bcode-laminar/src/plugin.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,23 @@ export const LaminarPlugin: Plugin = ({ client }) => {
8282
// this hook from its top-level finally before forceFlush, so span.end()
8383
// here gets its export drained by the host's existing forceFlush race.
8484
shutdown: () => {
85-
for (const [sessionId, span] of Object.entries(sessionCurrentTurnSpan)) {
86-
span.end()
85+
// Use console.error not client.app.log — the SDK server may already be
86+
// torn down by shutdown time, and the host log is async via HTTP which
87+
// doesn't honor the sync shutdown contract. v4-worker captures stderr
88+
// into bcode-output-<runId>.log so this lands in the cloud artifact.
89+
const sessionIds = Object.keys(sessionCurrentTurnSpan)
90+
console.error(`[bcode-laminar] shutdown invoked: ending ${sessionIds.length} turn span(s)`)
91+
for (const sessionId of sessionIds) {
92+
const span = sessionCurrentTurnSpan[sessionId]
93+
if (!span) continue
94+
try {
95+
span.end()
96+
} catch (err) {
97+
console.error(`[bcode-laminar] span.end() threw for session ${sessionId}: ${(err as Error).message}`)
98+
}
8799
delete sessionCurrentTurnSpan[sessionId]
88100
}
101+
console.error(`[bcode-laminar] shutdown complete`)
89102
},
90103
event: async ({ event }) => {
91104
switch (event.type) {

packages/opencode/src/index.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,26 +259,47 @@ try {
259259
// before forceFlush + process.exit() below.
260260
try {
261261
const { pluginShutdownHooks } = await import("./plugin")
262+
// Diagnostic via stderr: v4-worker captures into bcode-output-<runId>.log
263+
// and we need to know whether this branch is even reached + how many hooks
264+
// ran. Remove once V4 telemetry verification is settled.
265+
process.stderr.write(`[bcode] shutdown: invoking ${pluginShutdownHooks.size} plugin shutdown hook(s)\n`)
266+
let invoked = 0
262267
for (const hook of pluginShutdownHooks) {
263268
try {
264269
hook()
270+
invoked++
265271
} catch (err) {
266272
Log.Default.error("plugin shutdown hook failed", { error: err })
273+
process.stderr.write(`[bcode] shutdown: hook threw: ${(err as Error).message}\n`)
267274
}
268275
}
276+
process.stderr.write(`[bcode] shutdown: invoked ${invoked}/${pluginShutdownHooks.size} hook(s) successfully\n`)
269277
} catch (err) {
270278
Log.Default.error("plugin shutdown import failed", { error: err })
279+
process.stderr.write(`[bcode] shutdown: import failed: ${(err as Error).message}\n`)
271280
}
272281
// Drain any registered OTel span processors (e.g. bcode-laminar) before
273282
// exiting so the just-ended turn spans actually hit the wire. Bounded with
274283
// a 3 s race so a wedged exporter cannot hang bcode on exit. Generic to any
275284
// OTel-based plugin, not laminar-specific.
276285
const provider = trace.getTracerProvider() as { forceFlush?: () => Promise<void> }
277286
if (provider.forceFlush) {
287+
process.stderr.write(`[bcode] shutdown: forceFlush starting\n`)
288+
const start = Date.now()
278289
await Promise.race([
279-
provider.forceFlush().catch(() => {}),
280-
new Promise<void>((resolve) => setTimeout(resolve, 3000)),
290+
provider.forceFlush().catch((err: Error) => {
291+
process.stderr.write(`[bcode] shutdown: forceFlush rejected: ${err.message}\n`)
292+
}),
293+
new Promise<void>((resolve) =>
294+
setTimeout(() => {
295+
process.stderr.write(`[bcode] shutdown: forceFlush timed out after 3000ms\n`)
296+
resolve()
297+
}, 3000),
298+
),
281299
])
300+
process.stderr.write(`[bcode] shutdown: forceFlush done in ${Date.now() - start}ms\n`)
301+
} else {
302+
process.stderr.write(`[bcode] shutdown: no forceFlush on global provider\n`)
282303
}
283304
// Some subprocesses don't react properly to SIGTERM and similar signals.
284305
// Most notably, some docker-container-based MCP servers don't handle such signals unless

0 commit comments

Comments
 (0)