-
Notifications
You must be signed in to change notification settings - Fork 287
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
Avoid running nested runloops in ThreadedZMQSocketChannel #831
Conversation
There is no need to await the Future object because it's received on the on_recv callback, and should already contain the result.
ccing @ccordoba12 because he seems to be a user for Spyder and may want to test the change. |
Hi @marc-etienne, can you please enable maintainer edits so I can push a fix for the linter? |
Apparently "Allow edits from maintainers" isn't available if forked repo sits in an organisation 🙄. I've given you write access directly instead. I see the the flake8 and mypy error in CI log, I'll look into it. |
Hey @marc-etienne, thanks for the ping! Qtconsole tests run here, so that should be enough, but given that this kind of changes can be very disruptive, I'll open a PR in Spyder and set it up to run against your PR to be extra sure. About the changes themselves, I think @davidbrochart is the best to review them. |
instead of more generic Awaitable. It's the type received from the SocketStream.on_recv callback.
Thanks @marc-etienne and @ccordoba12! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @marc-etienne, I think you're right about not awaiting the message in another event loop.
I would actually go further, because I think the on_recv
callback is called with the message itself, not a Future
for it.
I'll push a commit with my suggestions to see it the Qtconsole tests pass, first.
jupyter_client/threaded.py
Outdated
@@ -114,13 +107,13 @@ def thread_send(): | |||
assert self.ioloop is not None | |||
self.ioloop.add_callback(thread_send) | |||
|
|||
def _handle_recv(self, future_msg: Awaitable) -> None: | |||
def _handle_recv(self, future_msg: asyncio.Future) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at pyzmq's documentation, shouldn't the argument already be the (multipart) message, not a Future
?
def _handle_recv(self, future_msg: asyncio.Future) -> None: | |
def _handle_recv(self, msg_list: List[bytes]) -> None: |
jupyter_client/threaded.py
Outdated
assert future_msg.done() | ||
msg_list = future_msg.result() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert future_msg.done() | |
msg_list = future_msg.result() |
317d0a4
to
bb2319c
Compare
Qtconsole's tests fail, suggesting that the argument to the |
I think the pyzmq doc on |
Let's clarify all that, and not try to guess the type of the argument at run-time. |
The short answer is: ThreadedKernelClient shouldn't use
The problem is the switch here to If there's a bug in pyzmq, it's that is creation of A class that uses ThreadedZMQSocketChannel should not be creating asyncio Sockets. You can always create multiple Python Socket objects for a single zmq socket with e.g. |
As part of #835, we properly use a synchronous socket for |
Hi!
I'm the maintainer of a project called IPyIDA, which integrates the QtConsole inside IDA Pro.
I'm using lots of plumbing to make this all work, and use QtKernelManager and QtKernelClient (which inherits from ThreadKernelClient) to connect to the kernel.
Since jupyter_client version 7, IPyIDA doesn't work and raises a RuntimeError and starting the client (see eset/ipyida#44). My temporary solution was to require working version of jupyter_client until I can find the source of the problem.
After much hours (probably too much :D) trying to understand the problem I think I found a proper solution. My understanding is that the
SocketStream.on_recv
was designed to be used with (pre-v6) Tornado runloop. Since Tornado 6, the Tornado runloop is just a wrapper around asyncio's.on_recv
still works with the asyncio runloop but receives the (completed) Future object with the result. Trying to await the Future in another runloop crashes because the callback is called from an already running runloop.The suggested commit fixes the problem with minimal changes because I didn't want to break other things I may not have full understanding about.