nb
nb14mo ago

Hand-rolled python client getting blocked from connecting?

Hey folks, I wrote my own python client because I wanted realtime updates. This has been working for the past few months, but recently stopped working and unfortunately triggered an unfortunate reconnect loop in a spot where I missed adding backoff. Sorry about that! I changed the version number for my connection from 0.3 -> 1.1, and that got it working again before I added the backoff (might have bypassed whatever block you folks put into place), but it stopped working again today. Now, I've added the backoff, but it seems I may have been manually blocked. It appears the connection initially happens, but then is immediately closed w error 1005 (internal) from websockets, which apparently is the error that comes from the websocket library when a connection is closed w out data sent. If you folks are manually blocking me, any chance I can get unblocked now that I've added exponential backoff (min 100ms, up to 10s per retry)?
File "/Users/nick/code/py-code/server/nickconvex.py", line 151, in recv
async for message in self.ws:
File "/Users/nick/.local/share/virtualenvs/py-code-a850zYJQ/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 497, in __aiter__
yield await self.recv()
^^^^^^^^^^^^^^^^^
File "/Users/nick/.local/share/virtualenvs/py-code-a850zYJQ/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 568, in recv
await self.ensure_open()
File "/Users/nick/.local/share/virtualenvs/py-code-a850zYJQ/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 944, in ensure_open
raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedError: received 1005 (no status code [internal]); then sent 1005 (no status code [internal])
File "/Users/nick/code/py-code/server/nickconvex.py", line 151, in recv
async for message in self.ws:
File "/Users/nick/.local/share/virtualenvs/py-code-a850zYJQ/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 497, in __aiter__
yield await self.recv()
^^^^^^^^^^^^^^^^^
File "/Users/nick/.local/share/virtualenvs/py-code-a850zYJQ/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 568, in recv
await self.ensure_open()
File "/Users/nick/.local/share/virtualenvs/py-code-a850zYJQ/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 944, in ensure_open
raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedError: received 1005 (no status code [internal]); then sent 1005 (no status code [internal])
9 Replies
ballingt
ballingt14mo ago
That's awesome! We are not manually blocking you. We don't consider the WebSocket protocol public (yet at least) so don't document it, but it should be very stable; we can't deprecate clients without a lot of notice. I made some changes to the server side recently that might have caused this change, but if you're sending the same messages as the Convex JS client you should be able to use this. However we don't suggest you do — the Convex Python client will soon support the WebSocket prtocol!
nb
nbOP14mo ago
Oh ok cool, I'll debug more on my end to figure out what's going on then. The behavior seemed like something was blocking me, but if that's not the case, I'll just spend a bit of time figuring out how the behavior changed and fix on my end.
ballingt
ballingt14mo ago
There's an open source Rust client that implements the protocol here: https://github.com/get-convex/convex-rs
GitHub
GitHub - get-convex/convex-rs: Rust client library for Convex
Rust client library for Convex. Contribute to get-convex/convex-rs development by creating an account on GitHub.
ballingt
ballingt14mo ago
We're in the process of wrapping this Rust code with the Python library so that we avoid having so many client implementations of the WebSocket protocol. In fact this is mostly done, I just haven't written the build scripts to produce Python wheels for every OS.
nb
nbOP14mo ago
Great to hear RE: official python client, I just have a small personal app that I'd like to use in the meantime so may end up spending a bit of time on this, but will stop if it's taking too long, and obviously I will be the first to implement the official python library when it supports realtime 🙂
ballingt
ballingt14mo ago
Once this us up there will be a low-level Python client that just barely wraps the WebSocket client, which you'll be able to wrap yourself if you want a different API that our official Python client provides. You could wrap this Rust client too, but it's a bit more hassle to build that code for every platform. I can't share the backend websocket code with you yet (open sourcing work is ongoing) so it's hard to know what's different — but if you follow the pattern of WebSocket messages that the client sends you should be ok. Does your connection time out or immediately disconnect? It looks like your client is receiving a close message, we'd send that if e.g. we received an unexpected message. I'd check that whatever the first few messages you send are have all fields that the JavaScript client does.
nb
nbOP14mo ago
Just to close the loop on this for anyone else following along, turns out there is a nice error message that started showing up once I turned on my websocket message logging. Will definitely make sure to check that next time. In the meantime, everything is fixed. Thanks again @ballingt!
sending {'type': 'Mutation', 'mutationId': 1, 'udfPath': 'tick.js', 'args': [{'sha': 'dev', 'release_ts': None}]}
sending {'type': 'ModifyQuerySet', 'baseVersion': 0, 'newVersion': 1, 'modifications': [{'type': 'Add', 'queryId': 1, 'udfPath': 'newRunAvailable.js:default', 'args': [{}]}]}
got message:
{"type":"FatalError","error":"Received Invalid JSON on websocket: missing field requestId"}
sending {'type': 'Mutation', 'mutationId': 1, 'udfPath': 'tick.js', 'args': [{'sha': 'dev', 'release_ts': None}]}
sending {'type': 'ModifyQuerySet', 'baseVersion': 0, 'newVersion': 1, 'modifications': [{'type': 'Add', 'queryId': 1, 'udfPath': 'newRunAvailable.js:default', 'args': [{}]}]}
got message:
{"type":"FatalError","error":"Received Invalid JSON on websocket: missing field requestId"}
ballingt
ballingt12mo ago
@nb there's a Python client prerelease installable with pip install convex==0.6.0a2 that'd I'd love to get your take on, it wraps the Rust client which uses the WebSocket protocol. See a demo here: https://colab.research.google.com/drive/19o5xpraHnfrh-fcOwqiLK-LpoxlWZNYx?usp=sharing Especially interested in your thoughts on usability compared to what you figured out.
nb
nbOP12mo ago
Oh awesome! Let me give this a shot at some point when I have a second... it might not be for a week or two.

Did you find this page helpful?