2

I am trying to create an app that uses websockets, but am running into the dreaded "multiple connection" issue where everytime the page is reloaded rather than closing and reopening a new websocket, another connection is simply added to the list. My question is if anyone knows the best/proper way to close a Socket.io websocket from Angular 2/4+.

Here's what I have as far as code:

service.ts

getUserSocket(userID: string): Observable<any> {
    return new Observable(_Observer => {

        // Setup the socket namespace subscription
        this.UserSocket = io(NTC_API_URL + `/user/${userID}`, { secure: true });

        this.UserSocket.on('message', _Message => {
            console.log(_Message);
        })
    })
}

closeUserSocket() {
    this.UserSocket.disconnect();
    this.UserSocket.close();
}

component.ts

ngOninit() {
    // Setup the User Socket
    this.UserSocket = this._UsersService.getUserSocket(this.currentUser.userID)
    .subscribe(_UserSocketMessage => {
        console.log(_UserSocketMessage);
    })
}

ngOnDestroy() {
    this.UserSocket.unsubscribe();
    this._UsersService.closeUserSocket();
}

This doesn't seem to be working as I can still watch the connections pile up just by logging in an out of the application which I have confirmed calls the component to be destroyed.

Another option I tried was using the once listener instead of the on listener, which worked, but I am unsure about the side effects and have read several places that it's not necessarily a fix for not closing the connection, which I can understand.

joshrathke
  • 7,564
  • 7
  • 23
  • 38
  • The `.disconnect` method should be called with a boolean value which indicates whether or not to close the underlying connection. So you should try calling `.disconnect(true)`. Ref: https://stackoverflow.com/a/31349392/5619416 – Alex Florin Aug 08 '17 at 14:17
  • Are you sure? My intellisense is screaming at me because the disconnect() method does not take any arguments. – joshrathke Aug 08 '17 at 14:23
  • Ahh, I think you were referrring to a `server` method and not a `client` method. The client is being used on the Angular side. – joshrathke Aug 08 '17 at 14:29
  • Another option could be to use the takeUntil() method on an observable, but I'm just not sure what I would be basing the statement on in terms of knowing when to close down the subscription. – joshrathke Aug 08 '17 at 23:30
  • Ah, I'm sorry. I thought that the method signatures are the same for client and server side. Well, as far as I know, `.disconnect()` and `.close()` should do the job, but, just for the sake of it, you could try emitting a special event from the client, say `closeConnection`, and on the server listen for it and call that `.disconnect(true)` method for the respective client. That might work. – Alex Florin Aug 09 '17 at 06:13

1 Answers1

1

After quite a bit of tinkering and research it occurred to me that web sockets are made to be resilient. In other words, since they were engineered to reconnect if possible, focusing on disconnect and close was the wrong approach. It was far easier to enforce policies with regard to the Creation of web socket connections.

For starters, I had to refactor a few things on the server side to make sure particular namespaces were only initialized once. This wasn't achieved so much by altering initialization code as it was by making sure that web socket initialization only occurred in places that either only happened on startup, or during processes that are only highly likely to happen once such as a particular user being created.

On the angular side it was also pretty straightforward in that all I had to do was assign the socket to a property within the service, then check if it existed before making the socket connection. Hence only creating the connection if no connection existed previously.

service.ts

// Setup the socket namespace subscription
if (!this.UserSocket) {
    // Initialize user permissions socket
    this.UserSocket = io(NTC_API_URL + `/user/${this.LocalUser.userID}`, { secure: true });
}
joshrathke
  • 7,564
  • 7
  • 23
  • 38