如何处理异步操作

概念

../_images/actions.png

在工作流执行期间,Mistral 最终会运行动作。动作是与工作流任务关联的特定函数(或工作)。

动作可以是同步的,也可以是异步的。

同步动作是在没有第三方的情况下完成的动作,即由 Mistral 本身完成。当 Mistral 引擎调度运行同步动作时,它会将动作的定义和参数发送到 Mistral 执行器,然后执行器运行它,并在完成时将动作的结果发送回 Mistral 引擎。

对于异步动作,执行器不会将结果发送回 Mistral。事实上,异步动作的概念假定在执行器运行时无法知道结果。相反,它假定动作只会将实际工作委托给第三方,该第三方可以是人类或计算机系统(例如,Web 服务)。因此,异步动作的 run() 方法应该只是向能够完成所需工作的对象发送信号。

一旦第三方完成了工作,它将负责通过 Mistral API 将动作的结果发送回 Mistral。实际上,第三方只需要更新相应动作执行对象的状态。为了实现这一点,它必须知道相应的动作执行 ID。

值得注意的是,从 Mistral 引擎的角度来看,同步和异步动作的模式本质上是相同的。如果动作是同步的,那么执行器在动作完成后会立即通过 RPC 机制(通常是消息队列作为传输)将结果发送回 Mistral 引擎。但引擎本身并没有主动等待任何内容,它的架构完全基于异步消息。因此,对于异步动作,唯一的改变是执行器不负责发送动作结果,而是由其他东西接管。

让我们看看在使用异步动作时需要注意什么。

如何操作

目前,Mistral 默认自带一个异步动作“mistral_http”。还有一个“async_noop”动作,它也是异步的,但主要用于测试目的,因为它什么也不做。“mistral_http”是动作“http”的异步版本,用于发送 HTTP 请求。异步性由动作的方法 is_sync() 控制,该方法应为同步动作返回 *True*,为异步动作返回 *False*。

让我们看看“mistral_http”动作是如何工作的以及如何逐步使用它。

我们可以想象,我们有一个简单的 Web 服务,充当前面提到的第三方系统,可以通过 http://my.webservice.com 访问。如果我们向该 URL 发送 HTTP 请求,我们的 Web 服务将执行一些有用的操作。为了简单起见,假设我们的 Web 服务只是计算作为请求参数“a”和“b”提供的两个数字之和。

1. 工作流示例

---
  version: '2.0'

  my_workflow:
    tasks:
      one_plus_two:
        action: mistral_http url=http://my.webservice.com
        input:
          params:
            a: 1
            b: 2

因此,我们的工作流只有一个任务“one_plus_two”,它向我们的 Web 服务发送请求,并在查询字符串中传递参数“a”和“b”。请注意,我们指定“url”在动作名称之后,而“params”在特殊的“input”部分。这是因为 Mistral 目前没有字典的一行语法。但“url”和“params”基本上只是动作“mistral_http”的参数。

重要的是要知道,当“mistral_http”动作发送请求时,它会包含特殊的 HTTP 标头,这些标头有助于识别动作执行对象。这些标头是

  • Mistral-Workflow-Name

  • Mistral-Workflow-Execution-Id

  • Mistral-Task-Id

  • Mistral-Action-Execution-Id

  • Mistral-Callback-URL

最重要的一个是“Mistral-Action-Execution-Id”,它包含我们需要计算结果的动作执行的 ID。第三方可以使用该 ID 一旦计算出结果,就可以将结果传递回 Mistral。如果第三方是计算机系统,它可以简单地通过 HTTP 调用 Mistral API,使用标头“Mistral-Callback-URL”,其中包含基本 URL。但是,人类也可以这样做,最简单的方法是使用 Mistral CLI。

当然,这只是一个毫无意义的示例。对于简单的算术运算,没有必要使用异步动作。需要异步动作的实际示例可能包括

  • 大数据量的分析。例如,我们需要运行外部报告工具。

  • 人工交互。例如,管理员需要批准资源分配。

通常,这可以是任何需要大量时间的事情,例如数小时、数天或数周。有时,作业的持续时间甚至可能是不可预测的(尽管在实践中尝试使用超时策略限制此类作业是合理的)。关键点是 Mistral 不应该尝试等待此类作业的完成,而应保留内存中所需的某些资源。

使用异步动作的一个重要方面是,即使我们与第三方的计算机系统交互,人类仍然可以通过简单地调用 Mistral API 来触发动作完成。

2. 将动作结果推送到 Mistral

使用 CLI

$ mistral action-execution-update <id> --state SUCCESS --output 3

此命令将使用相应的 ID 更新动作执行对象的“state”和“output”。这样,Mistral 就会知道此动作的结果是什么,并决定如何继续执行工作流。

使用原始 HTTP

POST <Mistral-Callback-URL>/v2/action-executions/<id>

{
  "state": "SUCCESS",
  "output": 3
}