async def _call_func(self, func: Callable, args: tuple, kwargs: Dict[str, Any], future: Future) -> None: def callback(f: Future) -> None: if f.cancelled(): self.call(scope.cancel) try: retval = func(*args, **kwargs) if iscoroutine(retval): with CancelScope() as scope: if future.cancelled(): scope.cancel() else: future.add_done_callback(callback) retval = await retval except self._cancelled_exc_class: future.cancel() except BaseException as exc: if not future.cancelled(): future.set_exception(exc) # Let base exceptions fall through if not isinstance(exc, Exception): raise else: if not future.cancelled(): future.set_result(retval) finally: scope = None # type: ignore[assignment]
def test_raise_if_exception_queued_cancels_futures(self, mock_wait): future = Future() self.assertFalse(future.cancelled()) # not initially cancelled self.executor.exceptions.put(self.workflow_exception) with self.assertRaisesRegex(WorkflowException, 'workflow exception'): self.executor.raise_if_exception_queued({future}, self.logger) self.assertTrue(mock_wait.called) self.assertTrue(future.cancelled()) # cancelled after exception called
def test_zip_cancel(): f_a = f_return("a") f_b = Future() f_c = Future() future = f_zip(f_a, f_b, f_c) future.cancel() assert f_b.cancelled() assert f_c.cancelled()
def job_stage_callback(job: Job, stage: str, fut: Future) -> None: ''' Generic job stage completion callback. Accepts a Job model, stage name, and the future. When this is called, it means the job stage has completed in some form or fashion. Should use `fut`'s result methods to figure out what happened and update accordingly. ''' # First, update job metadata with the execution result. exc = fut.exception() if not fut.cancelled() and exc: raise exc if fut.done(): job.meta_update(result=fut.result()) job.save() # Dispatch the next futures chain, if applicable if stage == STAGE_FETCHING: # Check if the job has any destinations and trigger the # destinations executor if 'destinations' in job.meta_dict: # Spawn the uploader future # TODO: Add a marker in the job meta showing # that destination uploads are queued job_begin_upload(job) elif stage == STAGE_UPLOADING: job.status = 'completed' job.save() log.info(f'job {job.id} has finished job pipeline')
def wrapped_func(*args, **kwargs): if threading.current_thread() is threading.main_thread(): return func(*args, **kwargs) cond = Condition() future = Future() def callback_func(dt): try: res = func(*args, **kwargs) with cond: future.set_result(res) cond.notify() except Exception as exc: with cond: future.set_exception(exc) cond.notify() finally: with cond: if not future.done(): future.cancel() cond.notify() with cond: Clock.schedule_once(callback_func, 0) cond.wait() assert future.done() if future.cancelled(): raise Exception("did not execute func %s" % func) if future.exception(): raise future.exception() return future.result()
def _future_done(self, future: Future): with self._lock: key = self._pending.inverse[future] if future.cancelled(): del self._pending[key] del self._promises[key] return try: result = future.result() self._cache[key] = result error = None except (AnalysisError, RuntimeError) as e: error = e if key not in self._promises: return if error is None: for promise in self._promises[key]: promise.set_result(result) else: for promise in self._promises[key]: promise.set_exception(error) del self._promises[key] del self._pending[key] with self._wait_condition: self._wait_condition.notify()
def _done_handler(base_future: Future): """Convert result of previous Future to result of new Future.""" if not base_future.done(): # Never True. Avoid infinite timeout. new_future.cancel() return if base_future.cancelled(): new_future.cancel() return try: result = base_future.result() if on_success: result = on_success(result) if isinstance(result, Future): # Defer resolution new_future new_future._chain_to_another_future(result) else: new_future.set_result(result) return except BaseException: ex, trace_back = sys.exc_info()[1:] if not on_fail: new_future.set_exception_info(ex, trace_back) return else: try: result = on_fail(ex) if isinstance(result, BaseException): raise result else: new_future.set_result(result) return except BaseException: ex, trace_back = sys.exc_info()[1:] new_future.set_exception_info(ex, trace_back) return
def _ready_callback(self, fn, mapping, proxy: Future, future: Future): """ Internally handles completion of dependencies """ with self._lock: if not proxy in self._pending: return del self._pending[proxy] if future.cancelled(): proxy.cancel() if not proxy.set_running_or_notify_cancel(): return exception = future.exception() if exception is not None: proxy.set_exception(exception) return if mapping is None: dependencies = future.result() else: dependencies = mapping(*future.result()) internal = self._executor.submit(fn, *dependencies) internal.add_done_callback(partial(self._done_callback, proxy))
def process_done(future: Future): nonlocal self self._tasks_number -= 1 if future.cancelled(): # process_task ended by cancel self.requeue_message(self.requeue_message( basic_deliver.delivery_tag) ) else: if future.exception(): exception = future.exception() if (not isinstance(exception, RequeueMessage) and not isinstance(exception, ChangeQueue)): self.log.exception(exception) self.requeue_message( basic_deliver.delivery_tag ) if isinstance(exception, ChangeQueue): if not self.running.is_set(): self.running.clear() self.log.info("Changing queues") self.stop_consuming() self._queue = self.another_queue( exception.host) self.running.set() else: self.acknowledge_message(basic_deliver.delivery_tag)
def mark_done(self, queue_num: int, cmd: Command, fn: Future): if fn.cancelled(): logging.error("Failed Task: " + str(cmd.TransactionID)) elif fn.done(): logging.debug("Finished Task: " + str(cmd.TransactionID)) res = fn.result() # This marks the transaction as completed, and stores the result internally. self.queue.MarkComplete(queue_num, cmd, res)
def test_job_done_callback_bails_out_if_canceled(self, mock_restore): future = Future() future.cancel() self.assertTrue(future.cancelled()) rsc = Mock() self.executor.job_done_callback(rsc, self.logger, future) self.assertEqual(mock_restore.call_args, call(rsc, self.logger)) self.assertTrue(self.executor.exceptions.empty())
def test_rpcfuture_cancellation(): rpc_fut = RPCFuture() fut = Future() rpc_fut.attach(fut) rpc_fut.cancel() assert fut.cancelled()
def task_done(future: Future) -> None: if not task_status_future.done(): if future.cancelled(): task_status_future.cancel() elif future.exception(): task_status_future.set_exception(future.exception()) else: exc = RuntimeError('Task exited without calling task_status.started()') task_status_future.set_exception(exc)
def test_no_result_copy_success(self): source = Future() target = Future() copy(source, target, copy_result=False) source.set_result(obj) self.assertFalse(target.cancelled()) self.assertFalse(target.done())
def test_no_result_copy_exception(self): source = Future() target = Future() copy(source, target, copy_result=False) source.set_exception(exc) self.assertFalse(target.cancelled()) self.assertFalse(target.done())
def test_no_cancel_copy_cancel(self): source = Future() target = Future() copy(source, target, copy_cancel=False) source.cancel() self.assertFalse(target.cancelled()) self.assertFalse(target.done())
def test_copy_exception(self): source = Future() target = Future() copy(source, target) source.set_exception(exc) self.assertFalse(target.cancelled()) self.assertTrue(target.done()) self.assertIs(target.exception(), exc)
def test_copy_success(self): source = Future() target = Future() copy(source, target) source.set_result(obj) self.assertFalse(target.cancelled()) self.assertTrue(target.done()) self.assertIsNone(target.exception()) self.assertIs(target.result(), obj)
def callback(future: Future): if future.cancelled() or future.exception(): publication_event.state_of_processing = 'FAILURE' if future.exception(): logger.error('error while producing %s of %s', publication_event.format_requested, publication_event.published_object.title(), exc_info=future.exception()) elif future.done(): publication_event.state_of_processing = 'SUCCESS' publication_event.save()
def test_zip_inner_cancel(): f_a = f_return("a") f_b = Future() f_c = Future() future = f_zip(f_a, f_b, f_c) assert f_b.cancel() # Cancelling the inner future should cause the outer # future to also become cancelled, as well as the # other inner futures. assert f_c.cancelled() assert future.cancelled()
def _future_done(self, future: Future): with self._lock: key = self._pending.inverse[future] if future.cancelled(): del self._pending[key] del self._callbacks[key] return try: result = future.result() self._done(key, result, True) except AnalysisError as e: self._done(e.task, e, False)
def _proxy_done(self, future: Future): """ Internally handles events for proxy futures, this means handling cancellation. """ with self._lock: if not future in self._pending: return dependency = self._pending[future] del self._pending[future] if future.cancelled(): dependency.cancel()
def _done_callback(self, proxy: Future, future: Future): """ Internally handles completion of executor future, copies result to proxy Args: fn (function): [description] future (Future): [description] """ if future.cancelled(): proxy.cancel() exception = future.exception() if exception is not None: proxy.set_exception(exception) else: result = future.result() proxy.set_result(result)
def _promise_cancelled(self, future: Future): if not future.cancelled(): return key = future.key with self._lock: if key not in self._promises: return False if future not in self._promises[key]: return False self._promises[key].remove(future) if len(self._promises[key]) == 0: self._pending[key].cancel()
def handle_done_future(self, future: futures.Future): self.pending.pop(future.key) if future.cancelled(): for c in self.cancel_callbacks: c(future.key, future) return try: r = future.result() self.results[future.key] = r except Exception as e: self.errors[future.key] = e for c in self.error_callbacks: c(future.key, e, future) return for c in self.success_callbacks: c(future.key, r, future)
def _done_handler(base_future: Future): """Convert return of previous Future to results of new Future.""" if not base_future.done(): # Never True. Avoid infinite timeout. self.cancel() return if base_future.cancelled(): self.cancel() return try: result = base_future.result() if isinstance(result, Future): self._chain_to_another_future(result) else: self.set_result(result) return except BaseException: ex, trace_back = sys.exc_info()[1:] self.set_exception_info(ex, trace_back) return
def process_done(future: Future): nonlocal self self._tasks_number -= 1 if future.cancelled(): # process_task ended by cancel self.requeue_message(self.requeue_message( basic_deliver.delivery_tag) ) else: if future.exception(): exception = future.exception() if not isinstance(exception, RequeueMessage): self.log.exception(exception) self.requeue_message( basic_deliver.delivery_tag ) else: self.acknowledge_message(basic_deliver.delivery_tag)
def _import_done(self, future: Future = None) -> None: """ function called, when import is done or canceled :param future: import executing future object :return: nothing """ self._logger.debug("import done") self._view.dockwidget.progress_bar_layout.setVisible(False) self._view.dockwidget.cancel_import.clicked.disconnect(self._stop_import) if (future is not None) and future.cancelled(): self._logger.warn("future run finished, import cancelled!") elif future is not None: self._logger.info("future run finished, import successful") self._logger.info("QThread finished") if self.__thread is not None: self._logger.debug("waiting for the end...") self.__thread.wait() self._logger.debug("at the end...") self.__thread = None
def _copy(self, src: Future, dst: Future) -> None: gotit = self._lock.acquire(blocking=False) if not gotit: return try: if self._fired: return self._fired = True if src.cancelled(): dst.cancel() return try: dst.set_result(src.result()) except Exception as e: dst.set_exception(e) finally: self._lock.release()
def callback(prev_future: Future): if prev_future.cancelled() or not prev_future.done(): next_future.cancel() return if prev_future.exception() is not None: if on_rejected is None: next_future.set_exception(prev_future.exception()) else: next_future.set_result(on_rejected(prev_future.exception())) return try: result = prev_future.result() if on_fulfilled is not None: result = on_fulfilled(result) if isinstance(result, Future): result = result.result() next_future.set_result(result) except BaseException as ex: if on_rejected is None: next_future.set_exception(ex) else: next_future.set_result(on_rejected(ex))
def callback(f: Future) -> None: if f.cancelled(): self.call(scope.cancel)
def handle_cancel(done_future: ThreadFuture): """Function to propagate a cancellation of the concurrent future up to the loop callback""" if done_future.cancelled(): self._loop.call_soon_threadsafe(handle.cancel)