Search code examples
pythonmultithreadingpython-3.xtornado

Tornado: error: cannot add/remove handle - multi_perform() already running


I am using Tornado to make some async requests, and want to make a request each second. I'm doing so as such:

from tornado.httpclient import AsyncHTTPClient
import tornado.ioloop

def repeat():
    HTTP_CLIENT.fetch(some_request, handle_response)
    threading.Timer(1, repeat).start()

AsyncHTTPClient.configure(max_clients=100)
HTTP_CLIENT = AsyncHTTPClient()
repeat()
tornado.ioloop.IOLoop.current().start()

This works for about a minute but then I get this error:

Exception in thread Thread-29: Traceback (most recent call last):
...

error: cannot add/remove handle - multi_perform() already running

I know that this is resulting from the fact that the IOLoop and AsyncHTTPClient should only be accessed from the thread where IOLoop.start() is called.

So how do I schedule my repeat() function to always run on the same thread where IOLoop.start() is called?


Solution

  • Tornado is not thread-safe, aside from add_callback. Don't use threading code to schedule a callback in Tornado; do this instead:

    def repeat():
        HTTP_CLIENT.fetch(some_request, handle_response)
        tornado.ioloop.IOLoop.current().add_timeout(timedelta(seconds=1), repeat)