Skip to content

Commit 88e7188

Browse files
committed
[lssh] force exit on stale web socket
1 parent 2a6498b commit 88e7188

File tree

1 file changed

+15
-6
lines changed

1 file changed

+15
-6
lines changed

src/local-ssh/proxy.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,15 @@ class WebSocketSSHProxy {
196196
localSession.onAuthenticating(async (e) => {
197197
this.flow.workspaceId = e.username ?? '';
198198
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+
})
200208
.then(async session => {
201209
this.sendUserStatusFlow('connected');
202210
pipeSession = session;
@@ -237,7 +245,7 @@ class WebSocketSSHProxy {
237245
}
238246
}
239247

240-
private async authenticateClient(username: string) {
248+
private async authenticateClient(username: string, onStale: () => void) {
241249
const workspaceInfo = await this.retryGetWorkspaceInfo(username);
242250
this.flow.instanceId = workspaceInfo.instanceId;
243251
this.flow.userId = workspaceInfo.userId;
@@ -246,13 +254,13 @@ class WebSocketSSHProxy {
246254
}
247255

248256
if (FORCE_TUNNEL) {
249-
return this.getTunnelSSHConfig(workspaceInfo);
257+
return this.getTunnelSSHConfig(workspaceInfo, onStale);
250258
}
251259
try {
252260
return await this.tryDirectSSH(workspaceInfo);
253261
} catch (e) {
254262
this.sendErrorReport(this.flow, e, 'try direct ssh failed');
255-
return this.getTunnelSSHConfig(workspaceInfo);
263+
return this.getTunnelSSHConfig(workspaceInfo, onStale);
256264
}
257265
}
258266

@@ -279,7 +287,7 @@ class WebSocketSSHProxy {
279287
}
280288
}
281289

282-
private async getTunnelSSHConfig(workspaceInfo: GetWorkspaceAuthInfoResponse): Promise<SshClientSession> {
290+
private async getTunnelSSHConfig(workspaceInfo: GetWorkspaceAuthInfoResponse, onStale: () => void): Promise<SshClientSession> {
283291
try {
284292
const workspaceWSUrl = `wss://${workspaceInfo.workspaceId}.${workspaceInfo.workspaceHost}`;
285293
const socket = new WebSocket(workspaceWSUrl + '/_supervisor/tunnel/ssh', undefined, {
@@ -306,7 +314,8 @@ class WebSocketSSHProxy {
306314
// sends out pings plus a conservative assumption of the latency.
307315
pingTimeout = setTimeout(() => {
308316
this.telemetryService.sendUserFlowStatus('stale', this.flow);
309-
socket.terminate();
317+
session.close(SshDisconnectReason.byApplication);
318+
onStale();
310319
}, pingPeriod + 1000);
311320
};
312321
const stopHearbeat = () => {

0 commit comments

Comments
 (0)