EventMesh Workflow 使用说明

June 29, 2026 · View on GitHub

版本: v1.0.0 | 更新时间: 2026-06-29


1. 快速开始

1.1 环境准备

依赖版本说明
Go≥ 1.18编译运行
MySQL≥ 5.7持久化存储
EventMesh-事件总线 / Catalog 服务

1.2 初始化数据库

mysql -u root -p < distribution/mysql-schema.sql

1.3 编译

make build
# 产物: bin/eventmesh-workflow

1.4 启动

# Controller (HTTP API)
./bin/eventmesh-workflow controller --config configs/controller.yaml

# Engine (Task Runner)
./bin/eventmesh-workflow engine --config configs/engine.yaml

Controller 默认端口见 configs/controller.yamlserver.port,Swagger 文档在 /swagger/index.html


2. DSL 编写指南

2.1 DSL 1.0.3 (推荐)

使用 document + do 结构:

document:
  dsl: '1.0.3'
  namespace: eventmesh.apache.org
  name: my-first-workflow
  version: '1.0.0'

do:
  - step1:
      call: http
      with:
        endpoint: https://api.example.com/data
      then: step2

  - step2:
      set:
        result: '${ .data.value }'
      then: end

2.2 DSL 0.8 (兼容)

使用 id + states 结构:

id: my-legacy-workflow
version: '1.0'
specVersion: '0.8'
start: FirstState
states:
  - name: FirstState
    type: operation
    actions:
      - functionRef:
          refName: "myFunction"
    transition: SecondState
  - name: SecondState
    type: operation
    actions:
      - functionRef:
          refName: "myFunction2"
    end: true
functions:
  - name: myFunction
    operation: file://app.yaml#action
    type: asyncapi

两种格式可混用,解析器自动检测。


3. 任务类型详解

3.1 call — 调用外部操作

- sendOrder:
    call: asyncapi
    with:
      operation: file://order.yaml#sendOrder
    then: nextStep

支持的 call 类型:

call 值with 参数解析行为
httpendpointHTTP 端点作为 operation name
asyncapioperation / channel / documentEventMesh catalog 查询
openapioperationId / operation / documentREST API 操作
grpcservice / methodgRPC 服务方法
a2aendpointA2A Agent URL

A2A 调用示例:

- askAgent:
    call: a2a
    with:
      endpoint: http://localhost:9090
    then: processResult

3.2 listen — 监听事件

- waitForEvent:
    listen:
      to:
        one:
          with:
            type: order.created
            source: store/order
    then: processOrder

3.3 switch — 条件分支

- checkResult:
    switch:
      - success:
          when: .status == "ok"
          then: handleSuccess
      - failure:
          when: .status == "error"
          then: handleError
      - otherwise:
          then: end

条件表达式使用 JQ 语法,.field 引用输入 JSON 字段。

3.4 set — 数据转换

- transform:
    set:
      fullName: '${ .firstName + " " + .lastName }'
      amount: '${ .price * .quantity }'
    then: nextStep

3.5 do — 子任务序列

- processBatch:
    do:
      - stepA:
          set:
            validated: true
      - stepB:
          set:
            enriched: true
    then: nextStep

do 内的子任务目前支持 setraise

3.6 fork — 并行分支

- parallelTasks:
    fork:
      branches:
        - notifyEmail:
            call: http
            with:
              endpoint: https://api.example.com/email
        - notifySMS:
            call: http
            with:
              endpoint: https://api.example.com/sms
    then: joinPoint

3.7 for — 循环迭代

- processItems:
    for:
      each: .items
      do:
        - enrichItem:
            set:
              processed: true
              timestamp: '${ now }'
    then: nextStep

3.8 try — 错误处理

- safeOperation:
    try:
      - riskyTask:
          call: http
          with:
            endpoint: https://api.example.com/may-fail
    catch:
      when:
        - fallback:
            set:
              status: fallback
              error: '${ .message }'
    then: continue

3.9 wait — 延迟

- pause:
    wait:
      seconds: '10s'
    then: nextStep

支持 Go duration 格式:10s, 1m, 500ms, 1h30m

3.10 raise — 抛出错误

- validate:
    set:
      error: '${ .result }'
    then: checkError

- checkError:
    switch:
      - hasError:
          when: .error != null
          then: raiseError
    then: end

- raiseError:
    raise:
      error:
        type: ValidationError
        status: '400'
        title: Input Validation Failed
        detail: '${ .error }'

3.11 run — 发布事件

- fireEvent:
    run:
      with:
        event: order.processed
    then: end

3.12 emit — 发出事件 (同 run)

- emitEvent:
    emit:
      event: notification.sent
    then: end

4. 数据输入输出

4.1 工作流级 input

document:
  dsl: '1.0.3'
  name: order-workflow
  version: '1.0.0'

input:
  from: ${ .order }

do:
  - step1:
      call: asyncapi
      with:
        operation: file://order.yaml#process

启动工作流时传入的 JSON 会通过 input.from 过滤后再传递给第一个任务。

4.2 任务级 input/output 过滤

- step1:
    call: http
    with:
      endpoint: https://api.example.com/data
    input:
      from: ${ { userId: .user.id, amount: .price } }
    output:
      as: ${ { result: .data } }
    then: step2
  • input.from: 从上游数据中提取字段作为本任务输入
  • output.as: 从本任务输出中提取字段传递给下游

4.3 内联数据

- step1:
    set:
      greeting: '${ "Hello, " + .name }'
    data: '{"name": "World"}'
    then: end

data 字段提供静态初始数据,优先级低于 input 传入的数据。


5. 调度配置

document:
  dsl: '1.0.3'
  name: daily-report
  version: '1.0.0'

schedule:
  start: '2026-07-01T00:00:00Z'
  cron: '0 0 9 * * ?'
  after: 'PT5M'

do:
  - generateReport:
      call: http
      with:
        endpoint: https://api.example.com/report
      then: end
字段说明
startISO 8601 时间,调度开始时间
cronCron 表达式
afterISO 8601 间隔 (PT5M = 5 分钟)

6. 流程控制

6.1 then 指令

then: nextTaskName    # 跳转到命名任务
then: end             # 终止工作流
then: exit            # 同 end
then: continue        # 同 end(当前未实现循环语义)

6.2 隐式顺序

如果任务未指定 then 而有嵌套子任务(do/fork/for/try),默认跳转到第一个子任务。


7. REST API 参考

7.1 工作流 CRUD

方法路径说明
POST/workflow创建/更新工作流
GET/workflow查询工作流列表
GET/workflow/:workflowId查询工作流详情
DELETE/workflow/:workflowId删除工作流
GET/workflow/instances查询运行实例

7.2 创建/更新工作流

curl -X POST http://localhost:8080/workflow \
  -H "Content-Type: application/json" \
  -d '{
    "workflow_id": "order-management",
    "workflow_name": "Order Management Workflow",
    "definition": "document:\n  dsl: \"1.0.3\"\n  name: order-management\n  version: \"1.0.0\"\n  namespace: eventmesh.apache.org\ndo:\n  - receiveOrder:\n      listen:\n        to:\n          one:\n            with:\n              type: online.store.newOrder\n      then: end"
  }'

注意: definition 是完整的 DSL YAML 文本,创建时 workflow_id 必须与 DSL 中的 document.nameid 一致。

7.3 查询工作流列表

curl "http://localhost:8080/workflow?page=1&size=20"

响应:

{
  "total": 10,
  "workflows": [
    {
      "workflow_id": "order-management",
      "workflow_name": "Order Management Workflow",
      "version": "1.0.0",
      "total_instances": 5,
      "total_running_instances": 3,
      "total_failed_instances": 2
    }
  ]
}

7.4 删除工作流

curl -X DELETE http://localhost:8080/workflow/order-management

执行软删除(status → -1),关联的任务、关系、实例同时标记。


8. A2A 集成

8.1 工作流作为 Agent

启动内置 A2A 端点:

agent := bridge.NewWorkflowAgent("my-workflow", "http://localhost:9090")
mux := http.NewServeMux()
agent.RegisterRoutes(mux)
http.ListenAndServe(":9090", mux)

外部 A2A Client 调用:

# 获取 Agent Card
curl http://localhost:9090/.well-known/agent-card.json

# 提交任务 (触发工作流执行)
curl -X POST http://localhost:9090/a2a/tasks \
  -H "Content-Type: application/json" \
  -d '{
    "message": {
      "role": "user",
      "parts": [{"type": "text", "text": "{\"order_id\": \"12345\"}"}]
    }
  }'

# 查询状态
curl http://localhost:9090/a2a/tasks/{task_id}

8.2 工作流调用 A2A Agent

在 DSL 中配置 call: a2a

- aiAnalysis:
    call: a2a
    with:
      endpoint: http://ai-agent:8080
    then: processResult

9. 完整示例

9.1 订单处理工作流 (DSL 1.0.3)

文件: configs/testcreateworkflow-v1.yaml

document:
  dsl: '1.0.3'
  namespace: eventmesh.apache.org
  name: store-order-management
  version: '1.0.0'

do:
  - receiveNewOrderEvent:
      listen:
        to:
          one:
            with:
              type: online.store.newOrder
              source: store/order
      then: checkNewOrderResult

  - checkNewOrderResult:
      switch:
        - newOrderSuccessful:
            when: .order_no != ""
            then: sendOrderPayment
        - newOrderFailed:
            then: end

  - sendOrderPayment:
      call: asyncapi
      with:
        operation: file://paymentapp.yaml#sendPayment
      then: checkPaymentStatus

  - checkPaymentStatus:
      switch:
        - paymentSuccessful:
            when: .order_no != ""
            then: sendOrderShipment
        - paymentDenied:
            then: end

  - sendOrderShipment:
      call: asyncapi
      with:
        operation: file://expressapp.yaml#sendExpress
      then: end

9.2 数据转换 + 并行处理

document:
  dsl: '1.0.3'
  name: data-pipeline
  version: '1.0.0'

do:
  - fetchData:
      call: http
      with:
        endpoint: https://api.example.com/raw-data
      then: transformData

  - transformData:
      set:
        normalized: '${ .data | map({ id, value: .amount * 100 }) }'
        timestamp: '${ now }'
      then: parallelNotify

  - parallelNotify:
      fork:
        branches:
          - emailNotify:
              call: http
              with:
                endpoint: https://api.example.com/email
          - slackNotify:
              call: http
              with:
                endpoint: https://api.example.com/slack
      then: end

10. 开发调试

10.1 运行测试

make test

测试覆盖:

测试数量内容
third_party/swf17V1/旧版解析、Fork/Try/For、Schedule/Output、校验、集成测试
internal/filter1JQ 过滤正常/异常路径

10.2 格式化

make fmt       # goimports + gofmt

10.3 代码检查

make lint      # golangci-lint

10.4 覆盖率

make cover     # 生成 HTML 覆盖率报告

10.5 本地调试技巧

  1. 使用 InMemoryQueue(配置 engine.yamlflow.queue.store: in-memory)避免依赖 EventMesh
  2. OperationTask 的 runA2AAction 可通过 Mock A2A Agent 验证
  3. LocalRuntimeTask 完全自包含,可独立测试

11. 配置参考

controller.yaml

server:
  port: 8080
  name: eventmesh-workflow-controller

database:
  dsn: "root:password@tcp(127.0.0.1:3306)/db_workflow?charset=utf8mb4&parseTime=True&loc=Local"
  max_idle_conns: 10
  max_open_conns: 100

engine.yaml

flow:
  protocol: eventmesh       # eventmesh | http
  queue:
    store: in-memory        # in-memory | eventmesh
    eventmesh:
      topic: workflow-task

catalog:
  server_name: eventmesh-catalog

12. 限制与规划

当前限制

项目说明
for 迭代body 内目前仅支持 set 任务
try/catchwhen 内的任务类型有限
嵌套 do运行时仅执行 set/raise,复杂子任务尚不支持
A2A streaming暂不支持流式响应
错误重试全局 retry_attempts=5,未按任务配置

规划功能

  • for/do/try 内完整任务类型支持
  • 子工作流调用 (subFlow)
  • 条件重试与超时配置
  • A2A 流式支持
  • WorkflowAgent 完整实例状态查询
  • DSL 1.0.3 auth/error/timeout 完整字段