@@ -293,9 +293,65 @@ function useDev({
293
293
`${ dashboardUrl } /projects/v3/${ config . project } `
294
294
) ;
295
295
296
- websocket . addEventListener ( "open" , async ( event ) => { } ) ;
297
- websocket . addEventListener ( "close" , ( event ) => { } ) ;
298
- websocket . addEventListener ( "error" , ( event ) => { } ) ;
296
+ const messageHandler = new ZodMessageHandler ( {
297
+ schema : serverWebsocketMessages ,
298
+ messages : {
299
+ SERVER_READY : async ( payload ) => {
300
+ for ( const worker of backgroundWorkerCoordinator . currentWorkers ) {
301
+ await sender . send ( "READY_FOR_TASKS" , {
302
+ backgroundWorkerId : worker . id ,
303
+ inProgressRuns : worker . worker . inProgressRuns ,
304
+ } ) ;
305
+ }
306
+ } ,
307
+ BACKGROUND_WORKER_MESSAGE : async ( payload ) => {
308
+ await backgroundWorkerCoordinator . handleMessage ( payload . backgroundWorkerId , payload . data ) ;
309
+ } ,
310
+ PONG : async ( ) => {
311
+ logger . debug ( "Received pong" , { timestamp : Date . now ( ) } ) ;
312
+ } ,
313
+ } ,
314
+ } ) ;
315
+
316
+ websocket . addEventListener ( "message" , async ( event ) => {
317
+ const data = JSON . parse (
318
+ typeof event . data === "string" ? event . data : new TextDecoder ( "utf-8" ) . decode ( event . data )
319
+ ) ;
320
+
321
+ await messageHandler . handleMessage ( data ) ;
322
+ } ) ;
323
+
324
+ const ping = new WebsocketPing ( {
325
+ callback : async ( ) => {
326
+ if ( websocket . readyState !== WebSocket . OPEN ) {
327
+ logger . debug ( "Websocket not open, skipping ping" ) ;
328
+ return ;
329
+ }
330
+
331
+ logger . debug ( "Sending ping" , { timestamp : Date . now ( ) } ) ;
332
+
333
+ await sender . send ( "PING" , { } ) ;
334
+ } ,
335
+ } ) ;
336
+
337
+ websocket . addEventListener ( "open" , async ( event ) => {
338
+ logger . debug ( "Websocket opened" , { event } ) ;
339
+
340
+ ping . start ( ) ;
341
+ } ) ;
342
+
343
+ websocket . addEventListener ( "close" , ( event ) => {
344
+ logger . debug ( "Websocket closed" , { event } ) ;
345
+
346
+ ping . stop ( ) ;
347
+ } ) ;
348
+
349
+ websocket . addEventListener ( "error" , ( event ) => {
350
+ logger . log ( `${ chalkError ( "Websocket Error:" ) } ${ event . error . message } ` ) ;
351
+ logger . debug ( "Websocket error" , { event, rawError : event . error } ) ;
352
+
353
+ ping . stop ( ) ;
354
+ } ) ;
299
355
300
356
// This is the deprecated task heart beat that uses the friendly attempt ID
301
357
// It will only be used if the worker does not support lazy attempts
@@ -361,34 +417,6 @@ function useDev({
361
417
} ) ;
362
418
} ) ;
363
419
364
- websocket . addEventListener ( "message" , async ( event ) => {
365
- const data = JSON . parse (
366
- typeof event . data === "string" ? event . data : new TextDecoder ( "utf-8" ) . decode ( event . data )
367
- ) ;
368
-
369
- const messageHandler = new ZodMessageHandler ( {
370
- schema : serverWebsocketMessages ,
371
- messages : {
372
- SERVER_READY : async ( payload ) => {
373
- for ( const worker of backgroundWorkerCoordinator . currentWorkers ) {
374
- await sender . send ( "READY_FOR_TASKS" , {
375
- backgroundWorkerId : worker . id ,
376
- inProgressRuns : worker . worker . inProgressRuns ,
377
- } ) ;
378
- }
379
- } ,
380
- BACKGROUND_WORKER_MESSAGE : async ( payload ) => {
381
- await backgroundWorkerCoordinator . handleMessage (
382
- payload . backgroundWorkerId ,
383
- payload . data
384
- ) ;
385
- } ,
386
- } ,
387
- } ) ;
388
-
389
- await messageHandler . handleMessage ( data ) ;
390
- } ) ;
391
-
392
420
let ctx : BuildContext | undefined ;
393
421
394
422
let firstBuild = true ;
@@ -972,3 +1000,34 @@ function createResolveEnvironmentVariablesFunction(configModule?: any) {
972
1000
return resolvedEnvVars ;
973
1001
} ;
974
1002
}
1003
+
1004
+ type WebsocketPingOptions = {
1005
+ callback : ( ) => Promise < void > ;
1006
+ pingIntervalInMs ?: number ;
1007
+ } ;
1008
+
1009
+ class WebsocketPing {
1010
+ private _callback : ( ) => Promise < void > ;
1011
+ private _pingIntervalInMs : number ;
1012
+ private _nextPingIteration : NodeJS . Timeout | undefined ;
1013
+
1014
+ constructor ( opts : WebsocketPingOptions ) {
1015
+ this . _callback = opts . callback ;
1016
+ this . _pingIntervalInMs = opts . pingIntervalInMs ?? 45_000 ;
1017
+ this . _nextPingIteration = undefined ;
1018
+ }
1019
+
1020
+ start ( ) {
1021
+ this . #sendPing( ) ;
1022
+ }
1023
+
1024
+ stop ( ) {
1025
+ clearTimeout ( this . _nextPingIteration ) ;
1026
+ }
1027
+
1028
+ #sendPing = async ( ) => {
1029
+ await this . _callback ( ) ;
1030
+
1031
+ this . _nextPingIteration = setTimeout ( this . #sendPing, this . _pingIntervalInMs ) ;
1032
+ } ;
1033
+ }
0 commit comments