In the 5.0.0 the following code no longer works and throws the error shown below. Is there still a way to start a tornado server in separate thread? For context, I'm using this for the (a self driving car project)[https://github.com/wroscoe/donkey] its web controller. This still works in v4.5.3.
import tornado.web
class WebServer(tornado.web.Application):
def __init__(self):
handlers = [ (r"/test", TestHandler), ]
settings = {'debug': True}
super().__init__(handlers, **settings)
def run(self, port=8886):
self.listen(port)
tornado.ioloop.IOLoop.instance().start()
class TestHandler(tornado.web.RequestHandler):
def get(self):
self.write("test success")
ws = WebServer()
from threading import Thread
t = Thread(target=ws.run, args=())
t.daemon = True
t.start()
Exception in thread Thread-4:
Traceback (most recent call last):
File "/home/wroscoe/miniconda3/envs/donkey/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/home/wroscoe/miniconda3/envs/donkey/lib/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "<ipython-input-1-65816933cb20>", line 12, in run
super().__init__(self.handlers, **self.settings)
File "/home/wroscoe/miniconda3/envs/donkey/lib/python3.6/site-packages/tornado/web.py", line 1961, in __init__
autoreload.start()
File "/home/wroscoe/miniconda3/envs/donkey/lib/python3.6/site-packages/tornado/autoreload.py", line 118, in start
io_loop = ioloop.IOLoop.current()
File "/home/wroscoe/miniconda3/envs/donkey/lib/python3.6/site-packages/tornado/ioloop.py", line 283, in current
loop = asyncio.get_event_loop()
File "/home/wroscoe/miniconda3/envs/donkey/lib/python3.6/asyncio/events.py", line 694, in get_event_loop
return get_event_loop_policy().get_event_loop()
File "/home/wroscoe/miniconda3/envs/donkey/lib/python3.6/asyncio/events.py", line 602, in get_event_loop
% threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'Thread-4'.
As it says, there is no current event loop in a new thread. So you have to create it.
This code works for me:
import asyncio
import tornado.web
class WebServer(tornado.web.Application):
def __init__(self):
handlers = [ (r"/test", TestHandler), ]
settings = {'debug': True}
super().__init__(handlers, **settings)
def run(self, port=8886):
self.listen(port)
tornado.ioloop.IOLoop.instance().start()
class TestHandler(tornado.web.RequestHandler):
def get(self):
self.write("test success")
ws = WebServer()
def start_server():
asyncio.set_event_loop(asyncio.new_event_loop())
ws.run()
from threading import Thread
t = Thread(target=start_server, args=())
t.daemon = True
t.start()
t.join()
Yeah, this is asyncio's policy which Tornado has inherited in 5.0. You must either create an event loop explicitly for each thread or use AnyThreadEventLoopPolicy.
This is not clear from tornado documentation, maybe we should change the documentation to make this clear?
Most helpful comment
As it says, there is no current event loop in a new thread. So you have to create it.
This code works for me: