# 外部任务

Camunda外部任务的工作原理基于任务拉取(pull)模式和数据库锁机制,核心设计思想是将耗时或特殊业务逻辑的处理从工作流引擎中分离出来,由外部系统异步完成。

Camunda引擎:工作流执行引擎,负责流程实例推进、任务创建和管理
外部任务表:数据库中的ACT_RU_EXT_TASK表,存储所有待处理的外部任务
外部工作者(Client):独立的应用程序,订阅特定topic,负责实际业务处理
REST API:引擎提供的接口,用于任务拉取、完成、失败等操作

# 安装

  • ruoyi分离版SecurityConfig放开权限
 requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
        // 静态资源,可匿名访问
        .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
        .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
        // Camunda REST API 允许匿名访问
        .antMatchers("/engine-rest/**").permitAll()
        // 除上面外的所有请求全部需要鉴权认证
        .anyRequest().authenticated();

服务端/engine-rest要放开给客户端订阅

  • maven 依赖
 <camunda.spring-boot.version>7.18.0</camunda.spring-boot.version>
<!-- 外部任务客户端 -->
<dependency>
    <groupId>org.camunda.bpm</groupId>
    <artifactId>camunda-external-task-client</artifactId>
    <version>${camunda.spring-boot.version}</version>
</dependency>
  • 服务端application.yml配置
camunda:
  bpm:
# rest api 无需授权  
    security:
      enabled: false
# rest api 登录信息      
#    admin-user:
#      id: admin
#      password: admin
    rest:
      enabled: true  # 确保REST API启用
    database:
      type: mysql
      schema-update: true   # 自动建表/更新
    history-level: full     # 便于调试
    # 以下是需要重点关注的配置
    job-execution:
      enabled: true  # 🔑 关键!启用作业执行器[4](@ref)
    auto-deployment-enabled: true  # 确保流程能自动部署
  • 客户端client配置
camunda:
  # 外部任务客户端配置
  client:
    enabled: true  # 是否启用外部任务客户端
    base-url: http://localhost:8080/engine-rest  # Camunda REST API 地址
    worker-id: ruoyi-external-task-worker  # 工作节点ID
    async-response-timeout: 2000  # 异步响应超时时间(毫秒)
    lock-duration: 1000  # 任务锁定持续时间(毫秒)
    max-tasks: 1  # 每次获取的最大任务数
    init-delay: 60  # 初始化延迟时间(秒),等待 REST API 启动
foo > 通过这个方式建立一个客户端应用,用于订阅服务端的主题,并且完成外部任务。

# 建模

foo

假设现在有一个需求, 我们要通过大模型生成视频, 这个生成视频任务需要耗费时间, 我们通过外部任务来完成这件事。

<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
  <bpmn:process id="Process_3179" name="外部任务" isExecutable="true">
    <bpmn:startEvent id="Event_0efb7gk">
      <bpmn:outgoing>Flow_0qhbz0z</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:sequenceFlow id="Flow_0qhbz0z" sourceRef="Event_0efb7gk" targetRef="Activity_166ty3l" />
    <bpmn:userTask id="Activity_166ty3l" name="表单" camunda:assignee="${startUser}">
      <bpmn:incoming>Flow_0qhbz0z</bpmn:incoming>
      <bpmn:outgoing>Flow_05iutp9</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:sequenceFlow id="Flow_05iutp9" sourceRef="Activity_166ty3l" targetRef="Activity_1p76r2e" />
    <bpmn:serviceTask id="Activity_1p76r2e" name="生成视频" camunda:type="external" camunda:topic="external-task-topic">
      <bpmn:incoming>Flow_05iutp9</bpmn:incoming>
      <bpmn:outgoing>Flow_0zxw1oa</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="Event_1dea3bv">
      <bpmn:incoming>Flow_0zxw1oa</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_0zxw1oa" sourceRef="Activity_1p76r2e" targetRef="Event_1dea3bv" />
  </bpmn:process>
</bpmn:definitions>

bpmn xml 建模文件

# 演示

foo

我们发起一个测试流程。

foo

通过流程高亮,我们可以看到外部任务,在处理

foo

select * from ACT_RU_EXT_TASK; 我们可以查询到订阅记录, 客户端就是查询这个信息进行订阅处理。

foo

通过日志,我们可以看到外部任务已经被客户端处理。