class AsyncResultWaiter(object): """ Class that makes waiting for an async result notification easy. Creates a subscriber for a generated token name, which can be handed to the async provider. The provider then publishes the result to the token name when ready. The caller can wait for the result or timeout. """ def __init__(self, process=None): self.process = process self.async_res = AsyncResult() self.wait_name = "asyncresult_" + create_simple_unique_id() if self.process: self.wait_name = self.wait_name + "_" + self.process.id # TODO: Use same mechanism as pooled RPC response endpoint (without the request) self.wait_sub = Subscriber(from_name=self.wait_name, callback=self._result_callback, auto_delete=True) self.activated = False def activate(self): if self.activated: raise BadRequest("Already active") self.listen_gl = spawn(self.wait_sub.listen ) # This initializes and activates the listener self.wait_sub.get_ready_event().wait(timeout=1) self.activated = True return self.wait_name def _result_callback(self, msg, headers): log.debug("AsyncResultWaiter: received message") self.async_res.set(msg) def await (self, timeout=None, request_id=None): try: result = self.async_res.get(timeout=timeout) if request_id and isinstance( result, AsyncResultMsg) and result.request_id != request_id: log.warn("Received result for different request: %s", result) result = None except gevent.Timeout: raise Timeout("Timeout in AsyncResultWaiter name={}".format( self.wait_name)) finally: self.wait_sub.deactivate() self.wait_sub.close() self.listen_gl.join(timeout=1) self.activated = False return result