@@ -196,7 +196,15 @@ class WebSocketSSHProxy {
196
196
localSession . onAuthenticating ( async ( e ) => {
197
197
this . flow . workspaceId = e . username ?? '' ;
198
198
this . sendUserStatusFlow ( 'connecting' ) ;
199
- e . authenticationPromise = this . authenticateClient ( e . username ?? '' )
199
+ e . authenticationPromise = this . authenticateClient ( e . username ?? '' , ( ) => {
200
+ // in case of stale connection ensure to trigger the reconnect asap
201
+ // try gracefully
202
+ localSession . close ( SshDisconnectReason . connectionLost ) ;
203
+ // but if not force exit
204
+ setTimeout ( ( ) => {
205
+ exitProcess ( true ) ;
206
+ } , 50 ) ;
207
+ } )
200
208
. then ( async session => {
201
209
this . sendUserStatusFlow ( 'connected' ) ;
202
210
pipeSession = session ;
@@ -237,7 +245,7 @@ class WebSocketSSHProxy {
237
245
}
238
246
}
239
247
240
- private async authenticateClient ( username : string ) {
248
+ private async authenticateClient ( username : string , onStale : ( ) => void ) {
241
249
const workspaceInfo = await this . retryGetWorkspaceInfo ( username ) ;
242
250
this . flow . instanceId = workspaceInfo . instanceId ;
243
251
this . flow . userId = workspaceInfo . userId ;
@@ -246,13 +254,13 @@ class WebSocketSSHProxy {
246
254
}
247
255
248
256
if ( FORCE_TUNNEL ) {
249
- return this . getTunnelSSHConfig ( workspaceInfo ) ;
257
+ return this . getTunnelSSHConfig ( workspaceInfo , onStale ) ;
250
258
}
251
259
try {
252
260
return await this . tryDirectSSH ( workspaceInfo ) ;
253
261
} catch ( e ) {
254
262
this . sendErrorReport ( this . flow , e , 'try direct ssh failed' ) ;
255
- return this . getTunnelSSHConfig ( workspaceInfo ) ;
263
+ return this . getTunnelSSHConfig ( workspaceInfo , onStale ) ;
256
264
}
257
265
}
258
266
@@ -279,7 +287,7 @@ class WebSocketSSHProxy {
279
287
}
280
288
}
281
289
282
- private async getTunnelSSHConfig ( workspaceInfo : GetWorkspaceAuthInfoResponse ) : Promise < SshClientSession > {
290
+ private async getTunnelSSHConfig ( workspaceInfo : GetWorkspaceAuthInfoResponse , onStale : ( ) => void ) : Promise < SshClientSession > {
283
291
try {
284
292
const workspaceWSUrl = `wss://${ workspaceInfo . workspaceId } .${ workspaceInfo . workspaceHost } ` ;
285
293
const socket = new WebSocket ( workspaceWSUrl + '/_supervisor/tunnel/ssh' , undefined , {
@@ -306,7 +314,8 @@ class WebSocketSSHProxy {
306
314
// sends out pings plus a conservative assumption of the latency.
307
315
pingTimeout = setTimeout ( ( ) => {
308
316
this . telemetryService . sendUserFlowStatus ( 'stale' , this . flow ) ;
309
- socket . terminate ( ) ;
317
+ session . close ( SshDisconnectReason . byApplication ) ;
318
+ onStale ( ) ;
310
319
} , pingPeriod + 1000 ) ;
311
320
} ;
312
321
const stopHearbeat = ( ) => {
0 commit comments