@@ -10,6 +10,7 @@ import { Disposable, DisposableCollection } from "@gitpod/gitpod-protocol";
10
10
import { repeat } from "@gitpod/gitpod-protocol/lib/util/repeat" ;
11
11
import { log } from "@gitpod/gitpod-protocol/lib/util/logging" ;
12
12
import { WsNextFunction , WsRequestHandler } from "./ws-handler" ;
13
+ import { ClientMetadata } from "../websocket/websocket-connection-manager" ;
13
14
14
15
/**
15
16
* This class provides a websocket handler that manages ping-pong behavior for all incoming websocket requests.
@@ -30,19 +31,20 @@ export class WsConnectionHandler implements Disposable {
30
31
try {
31
32
switch ( ws . readyState ) {
32
33
case websocket . CLOSED :
33
- // ws should not be in the clients list anymore, but still happens:
34
- // we rely on a 'close' event being generated, but never receive it. At the same time, the readyState is 'CLOSED' (3).
35
- // judging from the ws source code, this might only happen if an earlier registered handler throws an (unhandled) error.
36
- log . warn ( "websocket in strange state" , { readyState : ws . readyState } ) ;
37
-
38
- // the following is a hack trying to mitigate the effects of leaking CLOSED websockets
39
- if ( process . env . EXPERIMENTAL_WS_TERMINATION ) {
40
- try {
41
- ( ws as any ) . emitClose ( ) ;
42
- log . warn ( "websocket (experimental): close emitted" ) ;
43
- } catch ( err ) {
44
- log . error ( "websocket (experimental): error on emit('close')" , err ) ;
45
- }
34
+ // (AT) for unknown reasons the expected `close` event was not emitted, otherwise this websocket would
35
+ // no longer be contained in the list of clients iterated over. make sure we release all resources bound
36
+ // to this client connection.
37
+ const emitClose = ( ws as any ) . emitClose ;
38
+ if ( typeof emitClose === "function" ) {
39
+ this . clients . delete ( ws ) ;
40
+
41
+ emitClose ( ) ;
42
+ log . warn (
43
+ "websocket in strange state. forcefully emitting a close event to release resources." ,
44
+ {
45
+ clientMetadata : ( ws as any ) . clientMetadata ,
46
+ } ,
47
+ ) ;
46
48
}
47
49
return ;
48
50
case websocket . CONNECTING :
@@ -89,6 +91,8 @@ export class WsConnectionHandler implements Disposable {
89
91
90
92
handler ( ) : WsRequestHandler {
91
93
return ( ws : websocket , req : express . Request , next : WsNextFunction ) => {
94
+ // attaching ClientMetadata to websocket to use it for logging on websocket errors
95
+ ( ws as any ) . clientMetadata = ClientMetadata . fromRequest ( req ) ;
92
96
// maintain set of clients
93
97
this . clients . add ( ws ) ;
94
98
ws . on ( "close" , ( ) => this . clients . delete ( ws ) ) ;
0 commit comments