A few of our devs upgraded to 3.8.1 and now get an error when calling listen on an HTTPServer object.
Here is the callstack:
File "C:\Temp\tornado_bugp\service.py", line 565, in _make_private_app
server = app.listen(
File "C:\Users\dev\.virtualenvs\tornado-web-app-LhID9pTb\lib\site-packages\tornado\web.py", line 2112, in listen
server.listen(port, address)
File "C:\Users\dev\.virtualenvs\tornado-web-app-LhID9pTb\lib\site-packages\tornado\tcpserver.py", line 152, in listen
self.add_sockets(sockets)
File "C:\Users\dev\.virtualenvs\tornado-web-app-LhID9pTb\lib\site-packages\tornado\tcpserver.py", line 165, in add_sockets
self._handlers[sock.fileno()] = add_accept_handler(
File "C:\Users\dev\.virtualenvs\tornado-web-app-LhID9pTb\lib\site-packages\tornado\netutil.py", line 279, in add_accept_handler
io_loop.add_handler(sock, accept_handler, IOLoop.READ)
File "C:\Users\dev\.virtualenvs\tornado-web-app-LhID9pTb\lib\site-packages\tornado\platform\asyncio.py", line 99, in add_handler
self.asyncio_loop.add_reader(fd, self._handle_events, fd, IOLoop.READ)
File "C:\Users\dev\AppData\Local\Programs\Python\Python38-32\Lib\asyncio\events.py", line 501, in add_reader
raise NotImplementedError
NotImplementedError
Here is our call to listen:
handlers = [
tornado.web.URLSpec(
r'/config',
_ConfigHandler
),
tornado.web.URLSpec(
r'/health',
_HealthHandler,
{
'service_state': service_state
}
),
tornado.web.URLSpec(
r'/shutdown',
_ShutdownHandler,
{
'service_state': service_state
}
),
tornado.web.URLSpec(
r'/status',
relayserver.StatusHandler,
{
'relay_server': relay_server,
'stats': stats
}
)
]
app = tornado.web.Application(
handlers
)
server = app.listen(
tornado.options.options.private_port,
tornado.options.options.private_address,
xheaders=True,
max_body_size=tornado.options.options.max_body_size,
idle_connection_timeout=tornado.options.options.idle_timeout
)
I double checked to make sure all the handlers actually exist and they do.
When changing to 3.7 either system wide or in a virtual environment this works without issue.
It appears you are using Windows. Python 3.8 changed the default event loop on Windows. Working around this is documented here: https://www.tornadoweb.org/en/stable/index.html#installation
Excellent.
Thanks so much.
Will this be fixed in tornado? For example adding this to tornado/platform/asyncio.py :
~~~~~~~
import sys
if sys.platform == 'win32':
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
~~~~~~~
Not that way, no: https://github.com/tornadoweb/tornado/issues/2608
I don't think it would be appropriate for Tornado itself to configure the selector event loop automatically, since it has drawbacks (less scalability than the proactor loop, the user may want to use another event loop entirely like uvloop). Applications using Tornado (like jupyter notebook) may wish to do so, though. Maybe there should even be some more magical way to choose the selector loop (an environment variable? a special package to install?) to avoid the need to build this in to each application, although i don't really like the idea of that much magic.
But an alternative idea has been worked on: https://github.com/tornadoweb/tornado/pull/2815
Most helpful comment
It appears you are using Windows. Python 3.8 changed the default event loop on Windows. Working around this is documented here: https://www.tornadoweb.org/en/stable/index.html#installation