Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asyncpong #983

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open

Asyncpong #983

wants to merge 20 commits into from

Conversation

bubbleboy14
Copy link
Collaborator

@bubbleboy14 bubbleboy14 commented Apr 23, 2024

This PR consists of a few things, with the general intention of improving asynchronous writes and reconnect behavior.

TL/DR: fixes #976 and #942 and #974

background

Running asynchronously (with rel dispatcher), I noticed a couple things.

Firstly, I was seeing an error (SSLEOFError) that occasionally occurred in the course of a write, in particular while sending a PONG (hence the name of this branch). I actually think I saw some ticket about this a while ago, but wasn't able to reproduce it at the time.

Secondly, I noticed that my on_reconnect callback wasn't being fired, and that reconnects weren't reliable - I had to handle some cases in an on_error handler.

reconnects

The reconnect-related fix is in WrappedDispatcher: the problem was that reconnect() (by way of timeout()) wasn't passing True (as reconnecting kwarg) to setSock(); I modified reconnect() and timeout() to address this - problem solved.

async writes

I figured this was happening due to my asynchronous usage of the socket - it was probably trying to write when there wasn't room in the write buffer or writes weren't available for some other reason. For reference, WebSocket.send_frame() (in the _core module, on line 340) is where an individual frame is sent.

The fix is to write asynchronously in custom dispatcher / async mode. I modified WebSocket._send() (line 562) to use the send() function on the dispatcher. DispatcherBase now has a send() function, which just calls _socket.send() (as WebSocket._send() did previously - so there is no change with the default sync dispatcher). WrappedDispatcher.send() uses dispatcher.buffwrite(), which is available in the latest version (0.4.9.17) of rel. The WebSocket constructor now takes a dispatcher kwarg, and saves it on self.

Back in the _app module, in WebSocketApp, create_dispatcher() takes a handleDisconnect kwarg, which is passed to WrappedDispatcher. Also in run_forever(): handleDisconnect(WebSocketConnectionClosedException, bool(reconnect)) lambda is passed (as handleDisconnect kwarg) to create_dispatcher() (which WrappedDispatcher.send() passes to buffwrite()); and setSock() passes the dispatcher to the WebSocket instance.

why the _dispatcher module?

I moved DispatcherBase, Dispatcher, SSLDispatcher, and WrappedDispatcher to the new _dispatcher module so that the _core module could non-circularly import DispatcherBase and WrappedDispatcher for the dispatcher kwarg type hint in the WebSocket constructor.

status

This is still something of a work in progress. I've been testing this branch, and for my use case it's performing better than the current master branch, but further testing would be a good idea.

Please test with your use case and LMK how it goes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

reconnection fails when server returns op_code = ABNF.OPCODE_CLOSE
1 participant