コード例 #1
0
ファイル: worker.py プロジェクト: GrimDerp/WALKOFF
    async def execute_trigger(self, trigger, trigger_data):
        """ Execute a trigger and ship the data """
        logger.debug(
            f"Echoing data from trigger: {trigger.name}-{self.workflow.execution_id}"
        )
        try:
            result = trigger(trigger_data)
            tmsg = NodeStatusMessage.success_from_node(
                trigger, self.workflow.execution_id, result, parameters={})
            await send_status_update(self.session, self.workflow.execution_id,
                                     tmsg)
            self.accumulator[trigger.id_] = result
            self.in_process.pop(trigger.id_)

        # TODO: can/should a trigger actually raise any exceptions?
        except Exception as e:
            logger.exception(
                f"Worker received error for {trigger.name}-{self.workflow.execution_id}"
            )
            await send_status_update(
                self.session, self.workflow.execution_id,
                NodeStatusMessage.failure_from_node(trigger,
                                                    self.workflow.execution_id,
                                                    result=repr(e),
                                                    parameters={}))
コード例 #2
0
    async def execute_transform(self, transform, parents):
        """ Execute an transform and ship its result """
        logger.debug(
            f"Attempting evaluation of: {transform.label}-{self.workflow.execution_id}"
        )
        try:
            result = transform(
                parents, self.accumulator)  # run transform on parent's result
            status = NodeStatusMessage.success_from_node(
                transform,
                self.workflow.execution_id,
                result,
                parameters={},
                started_at=transform.started_at)
            logger.info(
                f"Transform {transform.label}-succeeded with result: {result}")

        except TransformException as e:
            logger.exception(
                f"Worker received error for {transform.name}-{self.workflow.execution_id}"
            )

            aeval = Interpreter()
            aeval(transform.transform)
            if len(aeval.error) > 0:
                error_tuple = (aeval.error[0]).get_error()
                ret = error_tuple[0] + "(): " + error_tuple[1]

            status = NodeStatusMessage.failure_from_node(
                transform,
                self.workflow.execution_id,
                result=ret,
                started_at=transform.started_at,
                parameters={})

        except Exception as e:
            logger.exception(
                f"Something bad happened in Transform evaluation: {e!r}")
            return

        # Send the status message through redis to ensure get_action_results completes it correctly
        await self.redis.xadd(self.results_stream,
                              {status.execution_id: message_dumps(status)})
コード例 #3
0
    async def evaluate_condition(self, condition, parents, children):
        """
            TODO: This will change when we implement a better UI element for it. For now, if an action is given a user
            defined name like "Hello World", it would be referenced by the variable name "Hello_World" in the
            conditional script. All whitespace in the action name is replaced by '_'. This is clearly problematic
            if a user has an action named "Hello World" as well as "Hello_World". In this case, we cannot be sure
            which is being referenced in the conditional and must raise an exception.
        """
        logger.debug(
            f"Attempting evaluation of: {condition.label}-{self.workflow.execution_id}"
        )
        try:
            child_id = condition(parents, children, self.accumulator)
            selected_node = children.pop(child_id)
            status = NodeStatusMessage.success_from_node(
                condition,
                self.workflow.execution_id,
                selected_node.name,
                parameters={},
                started_at=condition.started_at)
            logger.info(
                f"Condition selected node: {selected_node.label}-{self.workflow.execution_id}"
            )

            # We preemptively schedule all branches of execution so we must cancel all "false" branches here
            for child in children.values():
                if self.parent_map[child.id_] == 1:
                    await self.cancel_subgraph(child)

        except ConditionException as e:
            logger.exception(
                f"Worker received error for {condition.name}-{self.workflow.execution_id}"
            )

            aeval = Interpreter()
            aeval(condition.conditional)
            if len(aeval.error) > 0:
                error_tuple = (aeval.error[0]).get_error()
                ret = error_tuple[0] + "(): " + error_tuple[1]

            status = NodeStatusMessage.failure_from_node(
                condition,
                self.workflow.execution_id,
                result=ret,
                parameters={},
                started_at=condition.started_at)
        except KeyError as e:
            logger.exception(
                f"Worker received error for {condition.name}-{self.workflow.execution_id}"
            )
            status = NodeStatusMessage.failure_from_node(
                condition,
                self.workflow.execution_id,
                result=
                "ConditionError(): ensure that a non-parent node is selected and that the node name is not a string.",
                parameters={},
                started_at=condition.started_at)

        except Exception as e:
            logger.exception(
                f"Something bad happened in Condition evaluation: {e!r}")
            return

        # Send the status message through redis to ensure get_action_results completes it correctly
        await self.redis.xadd(self.results_stream,
                              {status.execution_id: message_dumps(status)})
コード例 #4
0
    async def execute_action(self, action: Action):
        """ Execute an action, and push its result to Redis. """
        # TODO: Is there a better way to do this?
        self.logger.handlers[0].stream.execution_id = action.execution_id
        self.logger.handlers[0].stream.workflow_id = action.workflow_id

        self.logger.debug(
            f"Attempting execution of: {action.label}-{action.execution_id}")
        self.current_execution_id = action.execution_id
        self.current_workflow_id = action.workflow_id

        results_stream = f"{action.execution_id}:results"

        if hasattr(self, action.name):
            # Tell everyone we started execution
            action.started_at = datetime.datetime.now()
            start_action_msg = NodeStatusMessage.executing_from_node(
                action, action.execution_id, started_at=action.started_at)
            await self.redis.xadd(
                results_stream,
                {action.execution_id: message_dumps(start_action_msg)})

            try:
                func = getattr(self, action.name, None)
                if callable(func):
                    if len(action.parameters) < 1:
                        result = await func()
                    else:
                        params = {}
                        for p in action.parameters:
                            if p.variant == ParameterVariant.GLOBAL:
                                key = config.get_from_file(
                                    config.ENCRYPTION_KEY_PATH, 'rb')
                                params[p.name] = fernet_decrypt(key, p.value)
                            else:
                                params[p.name] = p.value
                        result = await func(**params)

                    action_result = NodeStatusMessage.success_from_node(
                        action,
                        action.execution_id,
                        result=result,
                        started_at=action.started_at)
                    self.logger.debug(
                        f"Executed {action.label}-{action.execution_id} "
                        f"with result: {result}")

                else:
                    self.logger.error(
                        f"App {self.__class__.__name__}.{action.name} is not callable"
                    )
                    action_result = NodeStatusMessage.failure_from_node(
                        action,
                        action.execution_id,
                        result="Action not callable",
                        started_at=action.started_at)

            except Exception as e:
                self.logger.exception(
                    f"Failed to execute {action.label}-{action.execution_id}")
                action_result = NodeStatusMessage.failure_from_node(
                    action,
                    action.execution_id,
                    result=repr(e),
                    started_at=action.started_at)

        else:
            self.logger.error(
                f"App {self.__class__.__name__} has no method {action.name}")
            action_result = NodeStatusMessage.failure_from_node(
                action,
                action.execution_id,
                result="Action does not exist",
                started_at=action.started_at)

        await self.redis.xadd(
            results_stream,
            {action.execution_id: message_dumps(action_result)})