@@ -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