Example #1
0
def _workflow_wrapper(self, factory, input_data, *extra_args):
    wf_kwargs = {}
    for dep_name, proxy in self.proxy_factory_registry.items():
        wf_kwargs[dep_name] = proxy(*extra_args)
    func = factory(**wf_kwargs)
    try:
        args, kwargs = self.deserialize_input(input_data)
    except Exception:
        logger.exception('Cannot deserialize the input:')
        raise ValueError('Cannot deserialize the input: %r' % (input_data,))
    result = func(*args, **kwargs)
    # Can't use directly isinstance(result, restart_type) because if the
    # result is a single result proxy it will be evaluated. This also
    # fixes another issue, on python2 isinstance() swallows any
    # exception while python3 it doesn't.
    if not is_result_proxy(result) and isinstance(result, restart_type):
        try:
            traversed_input, (error, placeholders) =  traverse_data(
                [result.args, result.kwargs])
        except Exception:
            logger.exception('Cannot traverse the restart arguments:')
            raise ValueError(
                'Cannot traverse the restart arguments: %r, %r' %
                result.args, result.kwargs)
        wait(error)  # raise if not None
        if placeholders:
            raise SuspendTask
        r_args, r_kwargs = traversed_input
        try:
            serialized_input = self.serialize_restart_input(*r_args, **r_kwargs)
        except Exception:
            logger.exception('Cannot serialize the restart arguments:')
            raise ValueError(
                'Cannot serialize the restart arguments: %r, %r' %
                result.args, result.kwargs)
        raise Restart(serialized_input)
    try:
        traversed_result, (error, placeholders) = traverse_data(result)
    except Exception:
        logger.exception('Cannot traverse the result:')
        raise ValueError('Cannot traverse the result: %r' % result)
    wait(error)
    if placeholders:
        raise SuspendTask
    try:
        return self.serialize_result(traversed_result)
    except Exception:
        logger.exception('Cannot serialize the result:')
        raise ValueError('Cannot serialize the result: %r' % (result,))
Example #2
0
 def __call__(self, *args, **kwargs):
     node_id = "%s-%s" % (self.trace_name, self.call_number)
     ((t_args, t_kwargs), (err, results)) = traverse_data(
         [args, kwargs], f=collect_err_and_results, initial=(None, None)
     )
     r = super(TracingProxy, self).__call__(*t_args, **t_kwargs)
     assert is_result_proxy(r)
     factory = r.__factory__
     factory.node_id = node_id
     if err is not None:
         self.tracer.schedule_activity(node_id, self.trace_name)
         self.tracer.flush_scheduled()
         error_factory = err.__factory__
         self.tracer.error(node_id, str(error_factory.value))
     for dep in results or []:
         self.tracer.add_dependency(dep.__factory__.node_id, node_id)
     return r
Example #3
0
    def __call__(self, *args, **kwargs):
        """Consult the execution history for results or schedule a new task.

        This is method gets called from the user workflow code.
        When calling it, the task it refers to can be in one of the following
        states: RUNNING, READY, FAILED, TIMEDOUT or NOTSCHEDULED.

        * If the task is RUNNING this returns a Placeholder. The Placeholder
          interrupts the workflow execution if its result is accessed by
          raising a SuspendTask exception.
        * If the task is READY this returns a Result object. Calling the result
          method on this object will just return the final value the task
          produced.
        * If the task is FAILED this returns an Error object. Calling the
          result method on this object will raise a TaskError exception
          containing the error message set by the task.
        * In case of a TIMEOUT this returns an Timeout object. Calling the
          result method on this object will raise TaskTimedout exception, a
          subclass of TaskError.
        * If the task was NOTSCHEDULED yet:
            * If any errors in arguments, propagate the error by returning
              another error.
            * If any placeholders in arguments, don't do anything because there
              are unresolved dependencies.
            * Finally, if all the arguments look OK, schedule it for execution.
        """
        task_exec_history = self.task_exec_history
        call_number = self.call_number
        self.call_number += 1
        r = placeholder()
        for retry_number, delay in enumerate(self.retry):
            if task_exec_history.is_timeout(call_number, retry_number):
                continue
            if task_exec_history.is_running(call_number, retry_number):
                break  # result = Placehloder
            if task_exec_history.has_result(call_number, retry_number):
                value = task_exec_history.result(call_number, retry_number)
                order = task_exec_history.order(call_number, retry_number)
                try:
                    value = self.deserialize_result(value)
                except Exception as e:
                    logger.exception('Error while deserializing the activity result:')
                    self.task_decision.fail(e)
                    break  # result = Placeholder
                r = result(value, order)
                break
            if task_exec_history.is_error(call_number, retry_number):
                err = task_exec_history.error(call_number, retry_number)
                order = task_exec_history.order(call_number, retry_number)
                r = error(err, order)
                break
            traversed_args, (err, placeholders) = traverse_data([args, kwargs])
            if err:
                r = copy_result_proxy(err)
                break
            if placeholders:
                break  # result = Placeholder
            t_args, t_kwargs = traversed_args
            try:
                input_data = self.serialize_input(*t_args, **t_kwargs)
            except Exception as e:
                logger.exception('Error while serializing the task input:')
                self.task_decision.fail(e)
                break  # result = Placeholder
            self.task_decision.schedule(call_number, retry_number, delay, input_data)
            break  # result = Placeholder
        else:
            # No retries left, it must be a timeout
            order = task_exec_history.order(call_number, retry_number)
            r = timeout(order)
        return r
Example #4
0
    def __call__(self, *args, **kwargs):
        """Consult the execution history for results or schedule a new task.

        This is method gets called from the user workflow code.
        When calling it, the task it refers to can be in one of the following
        states: RUNNING, READY, FAILED, TIMEDOUT or NOTSCHEDULED.

        * If the task is RUNNING this returns a Placeholder. The Placeholder
          interrupts the workflow execution if its result is accessed by
          raising a SuspendTask exception.
        * If the task is READY this returns a Result object. Calling the result
          method on this object will just return the final value the task
          produced.
        * If the task is FAILED this returns an Error object. Calling the
          result method on this object will raise a TaskError exception
          containing the error message set by the task.
        * In case of a TIMEOUT this returns an Timeout object. Calling the
          result method on this object will raise TaskTimedout exception, a
          subclass of TaskError.
        * If the task was NOTSCHEDULED yet:
            * If any errors in arguments, propagate the error by returning
              another error.
            * If any placeholders in arguments, don't do anything because there
              are unresolved dependencies.
            * Finally, if all the arguments look OK, schedule it for execution.
        """
        task_exec_history = self.task_exec_history
        call_number = self.call_number
        self.call_number += 1
        r = placeholder()
        for retry_number, delay in enumerate(self.retry):
            if task_exec_history.is_timeout(call_number, retry_number):
                continue
            if task_exec_history.is_running(call_number, retry_number):
                break  # result = Placehloder
            if task_exec_history.has_result(call_number, retry_number):
                value = task_exec_history.result(call_number, retry_number)
                order = task_exec_history.order(call_number, retry_number)
                try:
                    value = self.deserialize_result(value)
                except Exception as e:
                    logger.exception(
                        'Error while deserializing the activity result:')
                    self.task_decision.fail(e)
                    break  # result = Placeholder
                r = result(value, order)
                break
            if task_exec_history.is_error(call_number, retry_number):
                err = task_exec_history.error(call_number, retry_number)
                order = task_exec_history.order(call_number, retry_number)
                r = error(err, order)
                break
            traversed_args, (err, placeholders) = traverse_data([args, kwargs])
            if err:
                r = copy_result_proxy(err)
                break
            if placeholders:
                break  # result = Placeholder
            t_args, t_kwargs = traversed_args
            try:
                input_data = self.serialize_input(*t_args, **t_kwargs)
            except Exception as e:
                logger.exception('Error while serializing the task input:')
                self.task_decision.fail(e)
                break  # result = Placeholder
            self.task_decision.schedule(call_number, retry_number, delay,
                                        input_data)
            break  # result = Placeholder
        else:
            # No retries left, it must be a timeout
            order = task_exec_history.order(call_number, retry_number)
            r = timeout(order)
        return r