Пример #1
0
 def history(self):
     # type: () -> Optional[History]
     if not isinstance(self._history, History):
         history = History(self._history)
         history.parse()
         return history
     return self._history
Пример #2
0
def test_workflow_with_repair_and_force_activities():
    workflow = ATestDefinitionWithInput
    history = builder.History(workflow, input={'args': [4]})

    # Now let's build the history to repair
    previous_history = builder.History(workflow, input={'args': [4]})
    decision_id = previous_history.last_id
    (previous_history.add_activity_task(
        increment,
        decision_id=decision_id,
        last_state='completed',
        activity_id='activity-tests.data.activities.increment-1',
        input={'args': 4},
        result=57)  # obviously wrong but helps see if things work
     )
    to_repair = History(previous_history)
    to_repair.parse()

    executor = Executor(DOMAIN,
                        workflow,
                        repair_with=to_repair,
                        force_activities="increment|something_else")

    # The executor should not schedule anything, it should use previous history
    decisions, _ = executor.replay(Response(history=history))
    assert len(decisions) == 1
    assert decisions[0]['decisionType'] == 'ScheduleActivityTask'
    attrs = decisions[0]['scheduleActivityTaskDecisionAttributes']
    assert not attrs['taskList']['name'].startswith("FAKE-")
    check_task_scheduled_decision(decisions[0], increment)
Пример #3
0
def profile(workflow_execution, nb_tasks=None):
    stats = WorkflowStats(History(workflow_execution.history()))

    header = (
        'Task',
        'Last State',
        'Scheduled',
        'Time Scheduled',
        'Start',
        'Time Running',
        'End',
        'Percentage of total time',
    )

    values = ((task, last_state,
               scheduled.strftime(TIME_FORMAT) if scheduled else None,
               (start - scheduled).total_seconds() if scheduled else None,
               start.strftime(TIME_FORMAT) if start else None,
               (end - start).total_seconds() if start else None,
               end.strftime(TIME_FORMAT) if end else None, percent)
              for task, last_state, scheduled, start, end, timing, percent in (
                  row for row in stats.get_timings_with_percentage()
                  if row is not None))
    rows = sorted(
        values,
        key=operator.itemgetter(5),
        reverse=True,
    )

    if nb_tasks:
        rows = rows[:nb_tasks]

    return header, rows
Пример #4
0
def get_task(workflow_execution, task_id, details=False):
    history = History(workflow_execution.history())
    history.parse()
    task = history.activities[task_id]
    header = [
        "type",
        "id",
        "name",
        "version",
        "state",
        "timestamp",
        "input",
        "result",
        "reason",
    ]
    # TODO...
    if details:
        header.append("details")
    # print >>sys.stderr, task
    state = task["state"]
    rows = [[
        task["type"],
        task["id"],
        task["name"],
        task["version"],
        state,
        task[state + "_timestamp"],
        task["input"],
        task.get("result"),  # Absent for failed tasks
        task.get("reason"),
    ]]
    if details:
        rows[0].append(task.get("details"))
    return header, rows
Пример #5
0
def get_task(workflow_execution, task_id, details=False):
    history = History(workflow_execution.history())
    history.parse()
    task = history._activities[task_id]
    header = [
        'type', 'id', 'name', 'version', 'state', 'timestamp', 'input',
        'result', 'reason'
    ]
    # TODO...
    if details:
        header.append('details')
    # print >>sys.stderr, task
    state = task['state']
    rows = \
        [
            [
                task['type'],
                task['id'],
                task['name'],
                task['version'],
                state,
                task[state + '_timestamp'],
                task['input'],
                task.get('result'),  # Absent for failed tasks
                task.get('reason'),
            ]]
    if details:
        rows[0].append(task.get('details'))
    return header, rows
Пример #6
0
def get_workflow_history(domain_name, workflow_id, run_id):
    domain = swf.models.Domain(domain_name)
    workflow_execution = (swf.querysets.WorkflowExecutionQuerySet(domain).get(
        workflow_id=workflow_id,
        run_id=run_id,
    ))

    return History(workflow_execution.history())
Пример #7
0
def fake_history():
    """
    Generates a SWF's History object like the SWF decider does, but from a fake
    workflow execution history stored in a json file in tests/data/dumps/.
    """
    with open("tests/data/dumps/workflow_execution_basic.json") as f:
        basic_history_tree = json.loads(f.read())
    basic_history = BasicHistory.from_event_list(basic_history_tree["events"])
    return History(basic_history)
Пример #8
0
def status(workflow_execution, nb_tasks=None):
    history = History(workflow_execution.history())
    history.parse()

    header = "Tasks", "Last State", "Last State Time", "Scheduled Time"
    rows = [(task["name"], ) + get_timestamps(task)
            for task in history.tasks[::-1]]
    if nb_tasks:
        rows = rows[:nb_tasks]

    return header, rows
Пример #9
0
def status(workflow_execution, nb_tasks=None):
    history = History(workflow_execution.history())
    history.parse()

    header = 'Tasks', 'Last State', 'Last State Time', 'Scheduled Time'
    rows = [(task['name'], ) + get_timestamps(task)
            for task in history._tasks[::-1]]
    if nb_tasks:
        rows = rows[:nb_tasks]

    return header, rows
Пример #10
0
def get_workflow_history(domain_name, workflow_id, run_id=None):
    """
    Get workflow history.
    :param domain_name:
    :type domain_name: str
    :param workflow_id:
    :type workflow_id: str
    :param run_id:
    :type run_id: str
    :return:
    :rtype: History
    """
    workflow_execution = get_workflow_execution(domain_name, workflow_id, run_id=run_id)
    return History(workflow_execution.history())
Пример #11
0
def test_last_state_times():
    """
    This test checks an execution with a single activity tasks.

    """
    history_builder = builder.History(ATestWorkflow)

    last_state = 'completed'
    activity_id = 'activity-tests.test_dataflow.increment-1'

    history_builder.add_activity_task(
        increment,
        decision_id=0,
        last_state=last_state,
        activity_id=activity_id,
    )

    history = History(history_builder)
    stats = WorkflowStats(history)
    total_time = stats.total_time()

    events = history.events
    assert total_time == (events[-1].timestamp -
                          events[0].timestamp).total_seconds()
    timings = stats.get_timings()[0]
    assert timings[0] == activity_id
    assert timings[1] == last_state

    TIMING_SCHEDULED = 2
    TIMING_STARTED = 3
    TIMING_COMPLETED = 4

    EV_SCHEDULED = -3
    EV_STARTED = -2
    EV_COMPLETED = -1

    assert timings[TIMING_SCHEDULED] == events[EV_SCHEDULED].timestamp
    assert timings[TIMING_STARTED] == events[EV_STARTED].timestamp
    assert timings[TIMING_COMPLETED] == events[EV_COMPLETED].timestamp

    TIMING_DURATION = 5
    assert timings[TIMING_DURATION] == (
        events[EV_COMPLETED].timestamp -
        events[EV_STARTED].timestamp).total_seconds()

    timings = stats.get_timings_with_percentage()[0]
    TIMING_TOTAL_TIME = -2
    TIMING_PERCENTAGE = -1
    percentage = (timings[TIMING_TOTAL_TIME] / total_time) * 100.
    assert percentage == timings[TIMING_PERCENTAGE]
Пример #12
0
def activity_rerun(domain, workflow_id, run_id, input, scheduled_id,
                   activity_id):
    # handle params
    if not activity_id and not scheduled_id:
        logger.error("Please supply --scheduled-id or --activity-id.")
        sys.exit(1)

    input_override = None
    if input:
        input_override = format.decode(input)

    # find workflow execution
    try:
        wfe = helpers.get_workflow_execution(domain, workflow_id, run_id)
    except (swf.exceptions.DoesNotExistError, IndexError):
        logger.error("Couldn't find execution, exiting.")
        sys.exit(1)
    logger.info("Found execution: workflowId={} runId={}".format(
        wfe.workflow_id, wfe.run_id))

    # now rerun the specified activity
    history = History(wfe.history())
    history.parse()
    task, args, kwargs, meta, params = helpers.find_activity(
        history,
        scheduled_id=scheduled_id,
        activity_id=activity_id,
        input=input_override,
    )
    kwargs["context"].update({
        "workflow_id": wfe.workflow_id,
        "run_id": wfe.run_id,
    })
    logger.debug("Found activity. Last execution:")
    for line in json_dumps(params, pretty=True).split("\n"):
        logger.debug(line)
    if input_override:
        logger.info("NB: input will be overriden with the passed one!")
    logger.info("Will re-run: {}(*{}, **{}) [+meta={}]".format(
        task, args, kwargs, meta))

    # download binaries if needed
    download_binaries(meta.get("binaries", {}))

    # execute the activity task with the correct arguments
    instance = ActivityTask(task, *args, **kwargs)
    result = instance.execute()
    if hasattr(instance, "post_execute"):
        instance.post_execute()
    logger.info("Result (JSON): {}".format(json_dumps(result, compact=False)))
Пример #13
0
def get_task(workflow_execution, task_id):
    history = History(workflow_execution.history())
    history.parse()
    task = history._activities[task_id]
    header = ('type', 'id', 'name', 'version', 'state', 'timestamp', 'input',
              'result')
    state = task['state']
    rows = [(
        task['type'],
        task['id'],
        task['name'],
        task['version'],
        state,
        task[state + '_timestamp'],
        task['input'],
        task['result'],
    )]
    return header, rows
Пример #14
0
def info(workflow_execution):
    history = History(workflow_execution.history())
    history.parse()

    if history.tasks:
        first_event = history.tasks[0]
        first_timestamp = first_event[first_event["state"] + "_timestamp"]
        last_event = history.tasks[-1]
        last_timestamp = (last_event.get("timestamp")
                          or last_event[last_event["state"] + "_timestamp"])
        workflow_input = first_event["input"]
    else:
        first_event = history.events[0]
        first_timestamp = first_event.timestamp
        last_event = history.events[-1]
        last_timestamp = last_event.timestamp
        workflow_input = first_event.input

    execution_time = (last_timestamp - first_timestamp).total_seconds()

    header = (
        "domain",
        "workflow_type.name",
        "workflow_type.version",
        "task_list",
        "workflow_id",
        "run_id",
        "tag_list",
        "execution_time",
        "input",
    )
    ex = workflow_execution
    rows = [(
        ex.domain.name,
        ex.workflow_type.name,
        ex.workflow_type.version,
        ex.task_list,
        ex.workflow_id,
        ex.run_id,
        ",".join(ex.tag_list),
        execution_time,
        workflow_input,
    )]
    return header, rows
Пример #15
0
def info(workflow_execution):
    history = History(workflow_execution.history())
    history.parse()

    if history.tasks:
        first_event = history.tasks[0]
        first_timestamp = first_event[first_event['state'] + '_timestamp']
        last_event = history.tasks[-1]
        last_timestamp = last_event.get('timestamp') or last_event[
            last_event['state'] + '_timestamp']
        workflow_input = first_event['input']
    else:
        first_event = history.events[0]
        first_timestamp = first_event.timestamp
        last_event = history.events[-1]
        last_timestamp = last_event.timestamp
        workflow_input = first_event.input

    execution_time = (last_timestamp - first_timestamp).total_seconds()

    header = (
        'domain',
        'workflow_type.name',
        'workflow_type.version',
        'task_list',
        'workflow_id',
        'run_id',
        'tag_list',
        'execution_time',
        'input',
    )
    ex = workflow_execution
    rows = [(
        ex.domain.name,
        ex.workflow_type.name,
        ex.workflow_type.version,
        ex.task_list,
        ex.workflow_id,
        ex.run_id,
        ','.join(ex.tag_list),
        execution_time,
        workflow_input,
    )]
    return header, rows
Пример #16
0
    def run(self, input=None):
        if input is None:
            input = {}
        args = input.get('args', ())
        kwargs = input.get('kwargs', {})
        self.create_workflow()

        self.initialize_history(input)

        self.before_replay()
        result = self.run_workflow(*args, **kwargs)

        # Hack: self._history must be available to the callback as a
        # simpleflow.history.History, not a swf.models.history.builder.History
        self._history = History(self._history)
        self._history.parse()
        self.after_replay()
        self.on_completed()
        self.after_closed()
        return result
Пример #17
0
    def replay(self, history):
        """Executes the workflow from the start until it blocks.

        """
        self.reset()

        self._history = History(history)
        self._history.parse()

        workflow_started_event = history[0]
        args = ()
        kwargs = {}
        input = workflow_started_event.input
        if input is None:
            input = {}
        args = input.get('args', ())
        kwargs = input.get('kwargs', {})

        try:
            result = self.run_workflow(*args, **kwargs)
        except exceptions.ExecutionBlocked:
            logger.info('{} open activities ({} decisions)'.format(
                self._open_activity_count,
                len(self._decisions),
            ))
            return self._decisions, {}
        except exceptions.TaskException, err:
            reason = 'Workflow execution error in task {}: "{}"'.format(
                err.task.name,
                getattr(err.exception, 'reason', repr(err.exception)))
            logger.exception(reason)

            details = getattr(err.exception, 'details', None)
            self.on_failure(reason, details)

            decision = swf.models.decision.WorkflowExecutionDecision()
            decision.fail(
                reason=swf.format.reason(reason),
                details=swf.format.details(details),
            )
            return [decision], {}
Пример #18
0
def activity_rerun(domain, workflow_id, run_id, input, scheduled_id,
                   activity_id):
    # handle params
    if not activity_id and not scheduled_id:
        logger.error("Please supply --scheduled-id or --activity-id.")
        sys.exit(1)

    input_override = None
    if input:
        input_override = json.loads(input)

    # find workflow execution
    try:
        wfe = helpers.get_workflow_execution(domain, workflow_id, run_id)
    except (swf.exceptions.DoesNotExistError, IndexError):
        logger.error("Couldn't find execution, exiting.")
        sys.exit(1)
    logger.info("Found execution: workflowId={} runId={}".format(
        wfe.workflow_id, wfe.run_id))

    # now rerun the specified activity
    history = History(wfe.history())
    history.parse()
    func, args, kwargs, params = helpers.find_activity(
        history,
        scheduled_id=scheduled_id,
        activity_id=activity_id,
        input=input_override,
    )
    logger.debug("Found activity. Last execution:")
    for line in json_dumps(params, pretty=True).split("\n"):
        logger.debug(line)
    if input_override:
        logger.info("NB: input will be overriden with the passed one!")
    logger.info("Will re-run: {}(*{}, **{})".format(func.__name__, args,
                                                    kwargs))

    # finally replay the function with the correct arguments
    result = func(*args, **kwargs)
    logger.info("Result (JSON): {}".format(json_dumps(result)))
Пример #19
0
def test_workflow_with_repair_if_task_failed():
    workflow = ATestDefinitionWithInput
    history = builder.History(workflow, input={'args': [4]})

    # Now let's build the history to repair
    previous_history = builder.History(workflow, input={'args': [4]})
    decision_id = previous_history.last_id
    (previous_history.add_activity_task(
        increment,
        decision_id=decision_id,
        last_state='failed',
        activity_id='activity-tests.data.activities.increment-1',
        input={'args': 4},
        result=57)  # obviously wrong but helps see if things work
     )
    to_repair = History(previous_history)
    to_repair.parse()

    executor = Executor(DOMAIN, workflow, repair_with=to_repair)

    # The executor should not schedule anything, it should use previous history
    decisions, _ = executor.replay(Response(history=history))
    check_task_scheduled_decision(decisions[0], increment)
Пример #20
0
    def replay(self, decision_response, decref_workflow=True):
        """Replay the workflow from the start until it blocks.
        Called by the DeciderWorker.

        :param decision_response: an object wrapping the PollForDecisionTask response
        :type  decision_response: swf.responses.Response
        :param decref_workflow : Decref workflow once replay is done (to save memory)
        :type decref_workflow : boolean

        :returns: a list of decision and a context dict (obsolete, empty)
        :rtype: ([swf.models.decision.base.Decision], dict)
        """
        self.reset()

        history = decision_response.history
        self._history = History(history)
        self._history.parse()
        self.build_execution_context(decision_response)
        self._execution = decision_response.execution

        workflow_started_event = history[0]
        input = workflow_started_event.input
        if input is None:
            input = {}
        args = input.get('args', ())
        kwargs = input.get('kwargs', {})

        self.before_replay()
        try:
            self.propagate_signals()
            result = self.run_workflow(*args, **kwargs)
        except exceptions.ExecutionBlocked:
            logger.info('{} open activities ({} decisions)'.format(
                self._open_activity_count,
                len(self._decisions),
            ))
            self.after_replay()
            if decref_workflow:
                self.decref_workflow()
            if self._append_timer:
                self._add_start_timer_decision('_simpleflow_wake_up_timer')
            return self._decisions, {}
        except exceptions.TaskException as err:
            reason = 'Workflow execution error in task {}: "{}"'.format(
                err.task.name,
                getattr(err.exception, 'reason', repr(err.exception)))
            logger.exception(reason)

            details = getattr(err.exception, 'details', None)
            self.on_failure(reason, details)

            decision = swf.models.decision.WorkflowExecutionDecision()
            decision.fail(
                reason=swf.format.reason(reason),
                details=swf.format.details(details),
            )
            self.after_closed()
            if decref_workflow:
                self.decref_workflow()
            return [decision], {}

        except Exception as err:
            reason = 'Cannot replay the workflow: {}({})'.format(
                err.__class__.__name__,
                err,
            )

            tb = traceback.format_exc()
            details = 'Traceback:\n{}'.format(tb)
            logger.exception(reason + '\n' + details)

            self.on_failure(reason)

            decision = swf.models.decision.WorkflowExecutionDecision()
            decision.fail(
                reason=swf.format.reason(reason),
                details=swf.format.details(details),
            )
            self.after_closed()
            if decref_workflow:
                self.decref_workflow()
            return [decision], {}

        self.after_replay()
        decision = swf.models.decision.WorkflowExecutionDecision()
        decision.complete(result=swf.format.result(json_dumps(result)))
        self.on_completed()
        self.after_closed()
        if decref_workflow:
            self.decref_workflow()
        return [decision], {}
Пример #21
0
def standalone(
    context,
    workflow,
    domain,
    workflow_id,
    execution_timeout,
    tags,
    decision_tasks_timeout,
    input,
    input_file,
    nb_workers,
    nb_deciders,
    heartbeat,
    display_status,
    repair,
    force_activities,
):
    """
    This command spawn a decider and an activity worker to execute a workflow
    with a single main process.

    """
    disable_boto_connection_pooling()

    if force_activities and not repair:
        raise ValueError(
            "You should only use --force-activities with --repair.")

    workflow_class = get_workflow(workflow)
    if not workflow_id:
        workflow_id = workflow_class.name

    wf_input = {}
    if input or input_file:
        wf_input = get_or_load_input(input_file, input)

    if repair:
        repair_run_id = None
        if " " in repair:
            repair, repair_run_id = repair.split(" ", 1)
        # get the previous execution history, it will serve as "default history"
        # for activities that succeeded in the previous execution
        logger.info('retrieving history of previous execution: domain={} '
                    'workflow_id={} run_id={}'.format(domain, repair,
                                                      repair_run_id))
        workflow_execution = get_workflow_execution(domain,
                                                    repair,
                                                    run_id=repair_run_id)
        previous_history = History(workflow_execution.history())
        repair_run_id = workflow_execution.run_id
        previous_history.parse()
        # get the previous execution input if none passed
        if not input and not input_file:
            wf_input = previous_history.events[0].input
        if not tags:
            tags = workflow_execution.tag_list
    else:
        previous_history = None
        repair_run_id = None
        if not tags:
            get_tag_list = getattr(workflow_class, 'get_tag_list', None)
            if get_tag_list:
                tags = get_tag_list(workflow_class, *wf_input.get('args', ()),
                                    **wf_input.get('kwargs', {}))
            else:
                tags = getattr(workflow_class, 'tag_list', None)
            if tags == Workflow.INHERIT_TAG_LIST:
                tags = None

    task_list = create_unique_task_list(workflow_id)
    logger.info('using task list {}'.format(task_list))
    decider_proc = multiprocessing.Process(
        target=decider.command.start,
        args=(
            [workflow],
            domain,
            task_list,
        ),
        kwargs={
            'nb_processes': nb_deciders,
            'repair_with': previous_history,
            'force_activities': force_activities,
            'is_standalone': True,
            'repair_workflow_id': repair or None,
            'repair_run_id': repair_run_id,
        },
    )
    decider_proc.start()

    worker_proc = multiprocessing.Process(
        target=worker.command.start,
        args=(
            domain,
            task_list,
        ),
        kwargs={
            'nb_processes': nb_workers,
            'heartbeat': heartbeat,
        },
    )
    worker_proc.start()

    print('starting workflow {}'.format(workflow), file=sys.stderr)
    ex = start_workflow.callback(
        workflow,
        domain,
        workflow_id,
        task_list,
        execution_timeout,
        tags,
        decision_tasks_timeout,
        format.input(wf_input),
        None,
        local=False,
    )
    while True:
        time.sleep(2)
        ex = helpers.get_workflow_execution(
            domain,
            ex.workflow_id,
            ex.run_id,
        )
        if display_status:
            print('status: {}'.format(ex.status), file=sys.stderr)
        if ex.status == ex.STATUS_CLOSED:
            print('execution {} finished'.format(ex.workflow_id),
                  file=sys.stderr)
            break

    os.kill(worker_proc.pid, signal.SIGTERM)
    worker_proc.join()
    os.kill(decider_proc.pid, signal.SIGTERM)
    decider_proc.join()
Пример #22
0
    def replay(self, decision_response):
        """Executes the workflow from the start until it blocks.

        :param decision_response: an object wrapping the PollForDecisionTask response
        :type  decision_response: swf.responses.Response

        :returns: a list of decision and a context dict
        :rtype: ([swf.models.decision.base.Decision], dict)
        """
        self.reset()

        history = decision_response.history
        self._history = History(history)
        self._history.parse()

        workflow_started_event = history[0]
        input = workflow_started_event.input
        if input is None:
            input = {}
        args = input.get('args', ())
        kwargs = input.get('kwargs', {})

        self.before_replay()
        try:
            result = self.run_workflow(*args, **kwargs)
        except exceptions.ExecutionBlocked:
            logger.info('{} open activities ({} decisions)'.format(
                self._open_activity_count,
                len(self._decisions),
            ))
            self.after_replay()
            return self._decisions, {}
        except exceptions.TaskException as err:
            reason = 'Workflow execution error in task {}: "{}"'.format(
                err.task.name,
                getattr(err.exception, 'reason', repr(err.exception)))
            logger.exception(reason)

            details = getattr(err.exception, 'details', None)
            self.on_failure(reason, details)

            decision = swf.models.decision.WorkflowExecutionDecision()
            decision.fail(
                reason=swf.format.reason(reason),
                details=swf.format.details(details),
            )
            self.after_closed()
            return [decision], {}

        except Exception as err:
            reason = 'Cannot replay the workflow: {}({})'.format(
                err.__class__.__name__,
                err,
            )

            tb = traceback.format_exc()
            details = 'Traceback:\n{}'.format(tb)
            logger.exception(reason + '\n' + details)

            self.on_failure(reason)

            decision = swf.models.decision.WorkflowExecutionDecision()
            decision.fail(
                reason=swf.format.reason(reason),
                details=swf.format.details(details),
            )
            self.after_closed()
            return [decision], {}

        self.after_replay()
        decision = swf.models.decision.WorkflowExecutionDecision()
        decision.complete(result=swf.format.result(json.dumps(result)))
        self.on_completed()
        self.after_closed()
        return [decision], {}
Пример #23
0
    def replay(self, decision_response, decref_workflow=True):
        # type: (swf.responses.Response, bool) -> DecisionsAndContext
        """Replay the workflow from the start until it blocks.
        Called by the DeciderWorker.

        :param decision_response: an object wrapping the PollForDecisionTask response
        :param decref_workflow : Decref workflow once replay is done (to save memory)

        :returns: a list of decision with an optional context
        """
        self.reset()

        # noinspection PyUnresolvedReferences
        history = decision_response.history
        self._history = History(history)
        self._history.parse()
        self.build_run_context(decision_response)
        # noinspection PyUnresolvedReferences
        self._execution = decision_response.execution

        workflow_started_event = history[0]
        input = workflow_started_event.input
        if input is None:
            input = {}
        args = input.get('args', ())
        kwargs = input.get('kwargs', {})

        self.before_replay()

        try:
            if self._history.cancel_requested:
                decisions = self.handle_cancel_requested()
                if decisions is not None:
                    self.after_replay()
                    self.after_closed()
                    if decref_workflow:
                        self.decref_workflow()
                    return DecisionsAndContext(decisions)
            self.propagate_signals()
            result = self.run_workflow(*args, **kwargs)
        except exceptions.ExecutionBlocked:
            logger.info('{} open activities ({} decisions)'.format(
                self._open_activity_count,
                len(self._decisions_and_context.decisions),
            ))
            self.after_replay()
            if decref_workflow:
                self.decref_workflow()
            if self._append_timer:
                self._add_start_timer_decision('_simpleflow_wake_up_timer')

            if not self._decisions_and_context.execution_context:
                self.maybe_clear_execution_context()

            return self._decisions_and_context
        except exceptions.TaskException as err:
            def _extract_reason(err):
                if hasattr(err.exception, 'reason'):
                    raw = err.exception.reason
                    # don't parse eventual json object here, since we will cast
                    # the result to a string anyway, better keep a json representation
                    return format.decode(raw, parse_json=False, use_proxy=False)
                return repr(err.exception)
            reason = 'Workflow execution error in task {}: "{}"'.format(
                err.task.name,
                _extract_reason(err))
            logger.exception('%s', reason)  # Don't let logger try to interpolate the message

            details = getattr(err.exception, 'details', None)
            self.on_failure(reason, details)

            decision = swf.models.decision.WorkflowExecutionDecision()
            decision.fail(
                reason=reason,
                details=details,
            )
            self.after_closed()
            if decref_workflow:
                self.decref_workflow()
            return DecisionsAndContext([decision])

        except Exception as err:
            reason = 'Cannot replay the workflow: {}({})'.format(
                err.__class__.__name__,
                err,
            )

            tb = traceback.format_exc()
            details = 'Traceback:\n{}'.format(tb)
            logger.exception('%s', reason + '\n' + details)  # Don't let logger try to interpolate the message

            self.on_failure(reason)

            decision = swf.models.decision.WorkflowExecutionDecision()
            decision.fail(
                reason=reason,
                details=details,
            )
            self.after_closed()
            if decref_workflow:
                self.decref_workflow()
            return DecisionsAndContext([decision])

        self.after_replay()
        decision = swf.models.decision.WorkflowExecutionDecision()
        decision.complete(result=result)
        self.on_completed()
        self.after_closed()
        if decref_workflow:
            self.decref_workflow()
        return DecisionsAndContext([decision])
Пример #24
0
def get_workflow_history(domain_name, workflow_id, run_id=None):
    workflow_execution = get_workflow_execution(domain_name,
                                                workflow_id,
                                                run_id=run_id)
    history = History(workflow_execution.history())
    return history