File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -59,7 +59,9 @@ const otelObservabilityPlugin = {
5959 // registering them later inside service.start() means our listeners
6060 // are never seen by the gateway. We register here and pass a lazy
6161 // telemetry getter; hooks no-op until start() has built the runtime.
62- registerHooks ( api , ( ) => telemetry , config ) ;
62+ // registerHooks returns a cleanup fn (clears the stale-session sweeper
63+ // interval) so service.stop() doesn't leak the timer across reloads.
64+ let stopHooks : ( ( ) => void ) | null = registerHooks ( api , ( ) => telemetry , config ) ;
6365
6466 // ── RPC: status endpoint ────────────────────────────────────────
6567
@@ -142,6 +144,10 @@ const otelObservabilityPlugin = {
142144 } ,
143145
144146 stop : async ( ) => {
147+ if ( stopHooks ) {
148+ stopHooks ( ) ;
149+ stopHooks = null ;
150+ }
145151 if ( unsubscribeDiagnostics ) {
146152 unsubscribeDiagnostics ( ) ;
147153 unsubscribeDiagnostics = null ;
Original file line number Diff line number Diff line change @@ -53,7 +53,7 @@ export function registerHooks(
5353 api : any ,
5454 getTelemetry : ( ) => TelemetryRuntime | null ,
5555 config : OtelObservabilityConfig
56- ) : void {
56+ ) : ( ) => void {
5757 const logger = api . logger ;
5858
5959 const buildSecurityCounters = ( counters : TelemetryRuntime [ "counters" ] ) : SecurityCounters => ( {
@@ -540,8 +540,10 @@ export function registerHooks(
540540 logger . info ( "[otel] Registered gateway:startup hook (via api.registerHook)" ) ;
541541
542542 // ── Periodic cleanup ─────────────────────────────────────────────
543- // Safety net: clean up stale session contexts (e.g., if agent_end never fires)
544- setInterval ( ( ) => {
543+ // Safety net: clean up stale session contexts (e.g., if agent_end never fires).
544+ // The handle is returned to the caller so service.stop() can clear it and
545+ // avoid leaking timers across plugin reload / shutdown.
546+ const cleanupInterval = setInterval ( ( ) => {
545547 const now = Date . now ( ) ;
546548 const maxAge = 5 * 60 * 1000 ; // 5 minutes
547549 for ( const [ key , ctx ] of sessionContextMap ) {
@@ -555,4 +557,8 @@ export function registerHooks(
555557 }
556558 }
557559 } , 60_000 ) ;
560+
561+ return ( ) => {
562+ clearInterval ( cleanupInterval ) ;
563+ } ;
558564}
You can’t perform that action at this time.
0 commit comments