jupyter-server / jupyter_server

The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications.
https://jupyter-server.readthedocs.io
BSD 3-Clause "New" or "Revised" License
484 stars 295 forks source link

Remove usages of tornado io_loop in favor of native asyncio #1362

Open blink1073 opened 10 months ago

blink1073 commented 10 months ago

Problem

Tornado's io_loop is now a wrapper around the native asyncio loop, and the tornado docs recommend using asyncio and asyncio.run() directly. In addition, there are plans to deprecate and remove asyncio.set_event_loop_policy, meaning that the we would have to use the loop_factory parameter that was added in Python 3.12.

We still want to use the SelectorEventLoop on Windows when using tornado, because even though it supports ProactorEventLoop as of tornado 6.1, it is less efficient, because it is using selectors in a thread.

Because ServerApp.io_loop is a public property, we'll have to bump to 3.0, because it is used by at least jupyterlab in a couple of places in tests (see below). We may also want to change it so that we start the event loop earlier, maybe in launch_instance.

Proposed Solution

We should remove usages of tornadio.io_loop up and down the stack, and add convenience function(s) in jupyter_core.utils to handle starting an event loop for different versions of Python, and perhaps a replacement for PeriodicCallback.

I will start by working on a PR to jupyter_client that replaces usages of ZMQStream.

Additional context

Known usages:

welcome[bot] commented 10 months ago

Thank you for opening your first issue in this project! Engagement like this is essential for open source projects! :hugs:
If you haven't done so already, check out Jupyter's Code of Conduct. Also, please try to follow the issue template as it helps other other community members to contribute more effectively. welcome You can meet the other Jovyans by joining our Discourse forum. There is also an intro thread there where you can stop by and say Hi! :wave:
Welcome to the Jupyter community! :tada:

blink1073 commented 10 months ago

Actually, we could still expose an ioloop object but have it be the asyncio loop, so you have an easy way to get the current running loop without calling a convenience function. We wouldn't have to change the usages in jupyterlab, but it would still be a breaking change.

minrk commented 10 months ago

👍 to switching all internal use to asyncio. There's little to no cost in keeping app.io_loop as a reference to IOLoop.current(), though (can be a deprecated property), so I don't think a breaking change is required, unless we change when that attribute is defined (we may), but it would still avoid ~all unnecessary breakage.

blink1073 commented 10 months ago

Good idea, thanks!