Search code examples
pythonpython-3.xpromisetornadofuture

confused by tornado.concurrent.Future exception


I'm trying to implement a variant of this question using tornado Futures. The queues a problem, because I don't want to past data being accumulated. IOW, I want the one http request handler to block waiting for result of another that occurs AFTER the original has started.

But I think I'm missing a step.

My code looks like:

Events = dict()

class EventHandler(tornado.web.RequestHandler):
    @tornado.gen.coroutine
    def get(self, unit):
        # create  future to block on
        future = tornado.concurrent.Future()
        # store the future at a place the produce can find it
        Events[unit] = future
        # block waiting for the future's response
        result = yield future.result()
        # deregister the future
        Events.pop(unit, None)
        self.write(result)

    @tornado.gen.coroutine
    def post(self, unit):
        # fetch the corresponding future if there is one
        future = Events.get(unit, None)
        if future:
            # found one, set the result to pass body over
            future.set_result(self.request.body)
        else:
            print('noop')
        self.write(bytes())

What happens is that I get errors that look like:

  File "./foo.py", line 44, in get
    result = yield future.result()
  File "/usr/lib/python3/dist-packages/tornado/concurrent.py", line 216, in result
    self._check_done()
  File "/usr/lib/python3/dist-packages/tornado/concurrent.py", line 294, in _check_done
    raise Exception("DummyFuture does not support blocking for results")

Am I not using the Future correctly? Is there an additional step I need to do in configuring it? Am I supposed to make a subclass that implements that _check_done behavior? Is my assumption that a tornado Future was synonymous with other systems calla a promise incorrect? Is there some different way to do this than just using a future/promise?


Solution

  • You need to use

    result = yield future
    

    Not

    result = yield future.result()
    

    yield future.result() is actually equivalent to yield <whatever is returned by future.result()>. If the result isn't ready yet, that means that the result() API would have to block (meaning, block the tornado event loop) until the result is ready, and tornado.concurrent.Future doesn't support that. You can only wait for the result using the non-blocking yield future construct.