0

Here a stackblitz of the problem:

https://stackblitz.com/edit/angular-ivy-jvm8pn?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2FMyWebsocketService.ts,src%2Fapp%2Fapp.component.html

How the hell do you (delete / destroy / release) a WebSocket instance???

export class MyWebsocketService {

    public url;

    _constructor( URL:string ) {
        this.connect();
    }
    
    connect() {        
        this.ws = new WebSocket(this.url);        
        this.ws.onopen = () => { // blablabla }
        this.ws.onmessage = () => { // blablabla }
        this.ws.onclose = () => { 

            /////// I CANNOT for the life of me destroy that WebSocket instance from memory
            /////// These are all the solutions online:

            this.ws.onopen = null;
            this.ws.onmessage = null;
            this.ws.onclose = null;
            this.ws.onerror = null;
            this.ws.close();
            this.ws = null;
            delete this.ws;

            setTimeout( _ => {
                console.log('Reconnecting...');
                this.connect();
            }, 3000);
        }
    }
}

...

public websocket;

createWebsocketsServices() {
    this.websocket = new MyWebsocketService('wss://whatever');
    
    // HERE I'm changing the URL
    this.websocket = new MyWebsocketService('wss://my-new-url');

    ////////// BUT THE  FIRST WEBSET IS STILL IN MEMORY!!!!!!!
}

ngOnInit(): void {
    this.createWebsocketsServices();
}

None of the solutions I found online actually resolve this issue

Understanding object creation and garbage collection of a NodeJS WebSocket server

WebSocket: How to automatically reconnect after it dies

How do you remove a native websocket handler when setting with ws.onmessage = myFunc; or ws.onopen = function(){}?

///////////// EDITED ////////////////////

"What makes you assume that the websocket is kept in memory?" A detail I forgot to mention is: in my real life application say I try to connect to 4 dummy URL and after I connect to the valid one... the ws server register 4 new connections not 1. They are still alive

My goals:

  1. Try to connect to websocket
  2. if can't connect try to reconnect every 3 seconds
  3. Change the websocket url on runtime = (Destroy current ws instance + create new ws instance with new URL)

That's a hack that works for now

https://stackblitz.com/edit/angular-ivy-vjezvq?file=src/app/app.component.ts

It doesn't resolve the issue the websocket is still not released from memory but I can at least change URL

Fractal Mind
  • 405
  • 4
  • 10
  • "*HERE THE SOCKET ARE STILL IN MEMORY*" - of course they are, they haven't been closed yet! The `onclose` handler wouldn't have been called. – Bergi Sep 24 '22 at 17:07
  • What is the actual problem you are trying to fix? – Bergi Sep 24 '22 at 17:08
  • https://stackblitz.com/edit/angular-ivy-jvm8pn?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2FMyWebsocketService.ts,src%2Fapp%2Fapp.component.html As you can see if you spam the button this won't release the websocket even after deconnection. It will still be in memory. The problem is with the reconnecting – Fractal Mind Sep 25 '22 at 19:35
  • I still don't get your problem. What do you see in the console? What makes you assume that the websocket is kept in memory? – Bergi Sep 25 '22 at 21:27
  • Notice that if you keep that `setTimeout(() => { this.connect(); }, 3000);` in your code, *that code* will keep the `MyWebsocketService` instance referenced and will reconnect it – Bergi Sep 25 '22 at 21:33
  • "What makes you assume that the websocket is kept in memory?" A detail I forgot to mention is: in my real life application say I try to connect to 4 dummy URL and after I connect to the valid one... the ws server register 4 new connections not 1. They are still alive – Fractal Mind Sep 25 '22 at 23:21
  • You might want to show your real life code then if you need a real life solution – Bergi Sep 25 '22 at 23:35

1 Answers1

0

When replacing one MyWebsocketService with another one, you'll need to disconnect the former one. Otherwise the web socket stays open, continues to receive messages, and will retain in memory all the callbacks that are registered to events and the things they reference. Overwriting the websocket variable will do nothing to prevent this, it does not "destroy" the object or release its memory, it just removes one reference to the object which would allow the garbage collector to collect the object if it wasn't referenced elsewhere - but it still is referenced from the open socket.

You'll want to do

export class MyWebsocketService {
    public url: string;
    public ws?: WebSocket;

    _constructor(url: string) {
        this.url = url;
    }
    
    connect() {        
        this.ws = new WebSocket(this.url);        
        this.ws.onopen = () => { // blablabla }
        this.ws.onmessage = () => { // blablabla }
        this.ws.onclose = () => { 
            this.ws = null;
        }
    }
    disconnect() {
        this.ws?.close();
    }
}

then

createWebsocketsServices() {
    this.websocket = new MyWebsocketService('wss://whatever');
    this.websocket.connect();
    
    // HERE I'm changing the URL:
    this.websocket.disconnect();
    this.websocket = new MyWebsocketService('wss://my-new-url');
    this.websocket.connect();
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • https://stackblitz.com/edit/angular-ivy-jvm8pn?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2FMyWebsocketService.ts,src%2Fapp%2Fapp.component.html As you can see if you spam the button this won't release the websocket. It will still be in memory. The problem is with the reconnecting – Fractal Mind Sep 25 '22 at 19:34