工作流引擎外部任务(External Tasks)下

处理外部任务(External Tasks)

要处理外部任务,必须在BPMN XML中声明它们。在运行时,可以通过Java和REST API访问外部任务实例。以下说明了API概念,并重点介绍了Java API。REST API通常更适合这种情况,特别是当使用不同的技术实现在不同环境中运行的工作程序时。

BPMN

在流程定义的BPMN XML中,可以使用属性pangubpm:type和声明服务任务由外部工作人员执行pangubpm:topic。例如,可以将服务任务验证地址配置为提供该主题的外部任务实例,AddressValidation如下所示:

<serviceTask id="validateAddressTask"

  name="Validate Address"

  pangubpm:type="external"

  pangubpm:topic="AddressValidation" />

可以通过使用表达式而不是常量值来定义主题名称。

此外,可以使用外部任务模式来实现其他类似服务任务的元素,例如发送任务,业务规则任务和引发消息事件。有关详细信息,请参见BPMN 2.0实现参考

Rest API

有关如何通过HTTP访问API操作的信息,请参阅REST API文档

长时间轮询以获取和锁定外部任务

无论请求的信息是否可用,服务器都会立即回答普通的HTTP请求。这不可避免地导致客户端必须执行多个重复请求,直到信息可用(轮询)。就资源而言,这种方法显然很昂贵。

在长时间轮询的帮助下,如果没有外部任务可用,服务器将挂起一个请求。一旦发生新的外部任务,该请求就会重新激活并执行响应。暂停被限制为可配置的时间段(超时)。

长轮询显着减少了请求数量,并使服务器和客户端都能更有效地使用资源。

当心!

该功能基于JAX-RS 2.0,因此在IBM WebSphere Application Server 8.5上不可用。

 

独特的工人要求

默认情况下,多个工作人员可以使用相同的workerId。为了确保workerId服务器端的唯一性,可以激活“唯一工人请求”标志。该配置标志仅影响长轮询请求,而不影响普通的“获取并锁定”请求。如果激活了“唯一工作人员请求”标志,workerId则在收到新请求时,具有该请求的未决请求将被取消。

为了使“独特的工人请求”标志,则engine-rest/WEB-INF/web.xml包含在文件引擎休息 神器需要通过设置环境参数调整fetch-and-lock-unique-worker-request到true。请考虑以下配置片段:

 

<!-- ... -->

<context-param>

  <param-name>fetch-and-lock-unique-worker-request</param-name>

  <param-value>true</param-value></context-param>

<!-- ... -->

Java API

用于外部任务的Java API的入口点是ExternalTaskService。可以通过访问processEngine.getExternalTaskService()。

以下是一个交互示例,该交互可提取10个任务,循环处理这些任务,并且对于每个任务,要么完成任务,要么将其标记为失败。

List<LockedExternalTask> tasks = externalTaskService.fetchAndLock(10, "externalWorkerId")

  .topic("AddressValidation", 60L * 1000L)

  .execute();

for (LockedExternalTask task : tasks) {

  try {

    String topic = task.getTopicName();

 

    // work on task for that topic

    ...

 

    // if the work is successful, mark the task as completed

    if(success) {

      externalTaskService.complete(task.getId(), variables);

    }

    else {

      // if the work was not successful, mark it as failed

      externalTaskService.handleFailure(

        task.getId(),

        "externalWorkerId",

        "Address could not be validated: Address database not reachable",

        1, 10L * 60L * 1000L);

    }

  }

  catch(Exception e) {

    //... handle exception

  }}

以下各节ExternalTaskService将更详细地介绍不同的交互。

抓取任务

为了实现轮询工作程序,可以使用方法执行获取操作ExternalTaskService#fetchAndLock。此方法返回一个流畅的构建器,该构建器允许定义一组主题以为其提取任务。考虑以下代码片段:

 

List<LockedExternalTask> tasks = externalTaskService.fetchAndLock(10, "externalWorkerId")

  .topic("AddressValidation", 60L * 1000L)

  .topic("ShipmentScheduling", 120L * 1000L)

  .execute();

for (LockedExternalTask task : tasks) {

  String topic = task.getTopicName();

 

  // work on task for that topic

  ...}

此代码最多可提取主题AddressValidation和的10个任务ShipmentScheduling。结果任务只为ID为的工作人员锁定externalWorkerId。锁定意味着从获取时间开始为该工作者保留任务一定时间,并防止在锁定有效时其他工作者可以获取同一任务。如果锁到期并且任务尚未完成,则其他工作人员可以获取该锁,以使发生故障的工作人员不会无限期地阻止执行。确切的持续时间在单个主题访存说明中给出:的任务AddressValidation被锁定60秒(60L * 1000L毫秒),而的任务ShipmentScheduling被锁定120秒(120L * 1000L毫秒)。锁定到期时间不应短于预期的执行时间。如果这意味着太长的超时时间(如果在工作人员无提示的情况下重试任务),则该时间也不应太高。

可以与任务一起获取执行任务所需的变量。例如,假设AddressValidation任务需要一个address变量。使用此变量获取任务可能类似于:

 

List<LockedExternalTask> tasks = externalTaskService.fetchAndLock(10, "externalWorkerId")

  .topic("AddressValidation", 60L * 1000L).variables("address")

  .execute();

for (LockedExternalTask task : tasks) {

  String topic = task.getTopicName();

  String address = (String) task.getVariables().get("address");

 

  // work on task for that topic

  ...}

然后,结果任务将包含所请求变量的当前值。请注意,变量值是从外部任务的执行在作用域层次结构中可见的值。有关详细信息,请参见“ 可变范围和可变可见性 ”一章。

为了获取所有变量,variables()应省略对方法的调用

 

List<LockedExternalTask> tasks = externalTaskService.fetchAndLock(10, "externalWorkerId")

  .topic("AddressValidation", 60L * 1000L)

  .execute();

for (LockedExternalTask task : tasks) {

  String topic = task.getTopicName();

  String address = (String) task.getVariables().get("address");

 

  // work on task for that topic

  ...}

为了对序列化变量值(通常是存储自定义Java对象的变量)进行反序列化,必须调用enableCustomObjectDeserialization()。否则,一旦从变量映射中检索到序列化变量,就会引发一个异常,即该对象未反序列化。

List<LockedExternalTask> tasks = externalTaskService.fetchAndLock(10, "externalWorkerId")

  .topic("AddressValidation", 60L * 1000L)

  .variables("address")

  .enableCustomObjectDeserialization()

  .execute();

for (LockedExternalTask task : tasks) {

  String topic = task.getTopicName();

  MyAddressClass address = (MyAddressClass) task.getVariables().get("address");

 

  // work on task for that topic

  ...}

外部任务优先级

 技术支持:盘古BPM工作流平台

相关教程