question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

'Error: WebSocket is not open' when closing two connected ws clients simultaneously

See original GitHub issue

Hi 👋 first of all, thanks for providing this awesome package - I am having great time using it. Unfortunately I ran into an issue, that I believe is not on my side (however I am happy to be proven wrong, or pointed to a valid solution).

Describe the bug When closing connections of two clients that are connected and notified of each other state via a common channel (e.g. a Subject), an Error: WebSocket is not open: readyState 2 (CLOSING) is thrown. Happens only when clients are closed immediately after another (e.g. via a script).

Full stack trace:

Error: WebSocket is not open: readyState 2 (CLOSING)
    at WebSocket.send (/*path to the project*//node_modules/@marblejs/websockets/node_modules/ws/lib/websocket.js:322:19)
    at WebSocket.sendResponse (/*path to the project*//node_modules/@marblejs/websockets/dist/response/websocket.response.handler.js:7:12)
    at SafeSubscriber.input$.pipe.subscribe.type [as _next] (/*path to the project*//node_modules/@marblejs/websockets/dist/server/websocket.server.listener.js:64:42)
    at SafeSubscriber.__tryOrUnsub (/*path to the project*//node_modules/rxjs/src/internal/Subscriber.ts:265:10)
    at SafeSubscriber.next (/*path to the project*//node_modules/rxjs/src/internal/Subscriber.ts:207:14)
    at Subscriber._next (/*path to the project*//node_modules/rxjs/src/internal/Subscriber.ts:139:22)
    at Subscriber.next (/*path to the project*//node_modules/rxjs/src/internal/Subscriber.ts:99:12)
    at TakeUntilSubscriber.Subscriber._next (/*path to the project*//node_modules/rxjs/src/internal/Subscriber.ts:139:22)
    at TakeUntilSubscriber.Subscriber.next (/*path to the project*//node_modules/rxjs/src/internal/Subscriber.ts:99:12)
    at CatchSubscriber.Subscriber._next (/*path to the project*//node_modules/rxjs/src/internal/Subscriber.ts:139:22)

To Reproduce

  1. Link two clients using a common channel.
  2. Using the finalize operator notify each user about another user being disconnected
  3. Open the connections
  4. Close the connections directly one after another (5.) First client that happens to be disconnected causes a message to be pushed to the second client, that also disconnected in the meantime. (6.) Message is being pushed, even though the websocket is in CLOSING state

Minimal epic causing the error:

class UserPoolPubSub {
    private readonly pubSub = new Subject<Message>();
    public join(id: string): Observable<Message> {
        this.publish(id, 'Hello there!');
        return this.pubSub.pipe(filter(({ publisher }) => publisher !== id));
    }
    public publish(publisher: string, message: string): void {
        this.pubSub.next({ publisher, message });
    }
}

const pool = new UserPoolPubSub();

const join$: WsEffect = (event$, { client: { id } }) => {
    const leave$ = event$.pipe(matchEvent('LEAVE'));

    return event$.pipe(
        matchEvent('JOIN'),
        exhaustMap(() =>
            pool.join(id).pipe(
                map(({ message }) => ({ type: 'RECEIVED', payload: message })),
                takeUntil(leave$),
            ),
        ),
        finalize(() => pool.publish(id, 'I was disconnected, sorry')),
    );
};

Minimal client interaction:

function run() {
// after opening the ws connections and exchanging messages
  clientA.close();
  clientB.close();
}

I published a runnable reproduction here: https://github.com/GrzegorzKazana/marblejs-ws-issue-repro. It can be run by

npm i
npm run dev
# in separate terminal
npm run client

Expected behavior Server should not try to push the event to user that is already closing.

Desktop (please complete the following information):

OS: MacOS 10.14.6
@marblejs/core: 3.4.8
@marblejs/websockets: 3.4.8
Node version: 12.18.0, also happens on 14.15.1

Additional context I run into this issue when doing integration tests for my app, that uses @marblejs/websocket for its backend. When the test runner was halting on a failed test, it caused closing all connections (2 in my case) at the same time - this in turned was causing crash of my backend service.

I hope I did not miss any obvious error on my side, but I will be happy to be corrected or pointed to a mistake.

Thanks in advance!

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
JozefFlakuscommented, Jan 27, 2021

Version 3.4.9 has been released 🚀

1reaction
GrzegorzKazanacommented, Jan 22, 2021

That’s a really accurate remark - I completely overlooked the fact that sendResponse is exposed to the user (via the client). Guess we can not change the public api too much then - so the option 3. does in fact seem to be the optimal way of going about it 🚀

Read more comments on GitHub >

github_iconTop Results From Across the Web

Error codes after closing websockets - Google Groups
Hi,. Since the latest weekly release, closing a websocket connection results in two possible return codes: EOF (the one as before) or "connection...
Read more >
Gorilla websocket is not closing - Stack Overflow
I want to open websocket server whenever i want to and close but server does not close after writing "exit" when i go...
Read more >
Both sides - websockets 10.4 documentation
If the corresponding Pong frame isn't received within ping_timeout seconds, the connection is considered unusable and is closed with code 1011. This ensures ......
Read more >
WebSockets support in ASP.NET Core - Microsoft Learn
When accepting the WebSocket connection before beginning the loop, the middleware pipeline ends. Upon closing the socket, the pipeline unwinds.
Read more >
error: websocket was closed before the connection ... - You.com
It happens when you call close() on websocket when connection is not established. The code you include in the question does not include...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found