@@ -23,6 +23,12 @@ interface PendingTunnelMessage {
2323 requestIdStr : string ;
2424}
2525
26+ class RunnerShutdownError extends Error {
27+ constructor ( ) {
28+ super ( "Runner shut down" ) ;
29+ }
30+ }
31+
2632export class Tunnel {
2733 #runner: Runner ;
2834
@@ -49,20 +55,31 @@ export class Tunnel {
4955 }
5056
5157 shutdown ( ) {
58+ // NOTE: Pegboard WS already closed at this point, cannot send
59+ // anything. All teardown logic is handled by pegboard-runner.
60+
5261 if ( this . #gcInterval) {
5362 clearInterval ( this . #gcInterval) ;
5463 this . #gcInterval = undefined ;
5564 }
5665
5766 // Reject all pending requests
67+ //
68+ // RunnerShutdownError will be explicitly ignored
5869 for ( const [ _ , request ] of this . #actorPendingRequests) {
59- request . reject ( new Error ( "Tunnel shutting down" ) ) ;
70+ request . reject ( new RunnerShutdownError ( ) ) ;
6071 }
6172 this . #actorPendingRequests. clear ( ) ;
6273
6374 // Close all WebSockets
75+ //
76+ // The WebSocket close event with retry is automatically sent when the
77+ // runner WS closes, so we only need to notify the client that the WS
78+ // closed:
79+ // https://github.com/rivet-dev/rivet/blob/00d4f6a22da178a6f8115e5db50d96c6f8387c2e/engine/packages/pegboard-runner/src/lib.rs#L157
6480 for ( const [ _ , ws ] of this . #actorWebSockets) {
65- ws . __closeWithRetry ( ) ;
81+ // TODO: Trigger close event, but do not send anything over the tunnel
82+ ws . __closeWithoutCallback ( 1000 , "ws.tunnel_shutdown" ) ;
6683 }
6784 this . #actorWebSockets. clear ( ) ;
6885 }
@@ -407,8 +424,16 @@ export class Tunnel {
407424 await this . #sendResponse( requestId , response ) ;
408425 }
409426 } catch ( error ) {
410- this . log ?. error ( { msg : "error handling request" , error } ) ;
411- this . #sendResponseError( requestId , 500 , "Internal Server Error" ) ;
427+ if ( error instanceof RunnerShutdownError ) {
428+ this . log ?. debug ( { msg : "catught runner shutdown error" } ) ;
429+ } else {
430+ this . log ?. error ( { msg : "error handling request" , error } ) ;
431+ this . #sendResponseError(
432+ requestId ,
433+ 500 ,
434+ "Internal Server Error" ,
435+ ) ;
436+ }
412437 } finally {
413438 // Clean up request tracking
414439 const actor = this . #runner. getActor ( req . actorId ) ;
0 commit comments