crossbario / crossbario/autobahn-python
Document onUserError
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 2.5k
- Forks
- 768
- PR merge metrics
- No merged PRs in 30d
Description
I'm writing a game application using autobahn, and first I encountered this issue at the application level and then realised it is relevant to the library.
I omit the imports assuming they are obvious.
Usecase
When opening a connection (or generally firing a callback of a protocol) I would like to shedule some async task.
So I write
class PlayerProtocol(WebSocketServerProtocol):
def onOpen(self):
asyncio.ensure_future(begin(), loop=loop)
Everything's ok, but when I occationnally break functionality of a coroutine begin()... nothing happens! No exception is raised. B-but why? I started an investigation.
The Rule
This investigation lead me to a simple rule: one should either await the task or handle the exceptions in a callback. What happens is pretty strightforward: the task is done with an exception, and as no one awaits for its result, the result (which is an exception in the case) is thrown away.
The same in the library
So I ended up with the callback that logs the exception, but glanced in a cource code and saw in asyncio/websocket.py:WebSocketAdapterProtocol these lines:
def _onOpen(self):
res = self.onOpen()
if yields(res):
ensure_future(res)
This is totally the same pattern that I implemented in my app: if self.onOpen() is a function, we're done, and if it is a coroutine (roughly), we shedule it. The other callbacks are the same.
Here we have an owerwhelming knowledge that onOpen and others may be a coroutine, but the docs says nothing about it. And I could throw away dancing with callbacks and just await begin()!. This is another issue, I will open it next. But...
But what if things in onOpen go wrong? Say,
class TrappingProtocol(WebSocketServerProtocol):
async def onOpen(self):
raise ValueError
Then we run it and try to connect with a simple client. And..?
You are right -- nothing happen. The user (a programmer) did not even notice the error.
A simplified example that should be enough to reproduce:
class TrappingProtocol(WebSocketServerProtocol):
async def onOpen(self):
raise ValueError
if __name__ == '__main__':
loop = asyncio.get_event_loop()
factory = WebSocketServerFactory()
factory.protocol = TrappingProtocol
coro = loop.create_server(factory, HOST, PORT)
server = loop.run_until_complete(coro)
try:
print('Server created.')
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
server.close()
loop.close()
A solution
Actually in this case I exepect that the server crash. Now in my app I implemented a callback which just logs the exception and stops the loop. Opening to discuss whether this solution is enough and ready to PR then if you giude me a little. (never did a PR on github thuogh)
Cheers!
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The issue points to asyncio/websocket.py and WebSocketAdapterProtocol._onOpen; start there to understand the callback behavior described. Update the documentation for onUserError and related callbacks to explain coroutine support and exception handling, with the provided example as the expected behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- documentation
- Issue type
- Documentation
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100