You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Temporal Go SDK v1.35.0模拟父子工作流时,子工作流仅接收首个信号后续信号丢失的问题排查

Temporal Go SDK v1.35.0模拟父子工作流时,子工作流仅接收首个信号后续信号丢失的问题排查

看起来问题的根源是父工作流在子工作流完成前就提前终止,导致Temporal测试环境直接杀死了子工作流,使得子工作流无法处理后续的SignalC信号。下面我们详细分析并给出修复方案:

问题流程梳理

我们先把当前代码的执行链路理清楚:

  1. 父工作流启动子工作流,发送SignalA给子工作流
  2. 子工作流收到SignalA,发送SignalB给父工作流
  3. 父工作流收到SignalB,发送SignalC给子工作流
  4. 父工作流发送完SignalC后直接return nil,自身标记为完成
  5. Temporal的TestWorkflowEnvironment有个默认行为:当根工作流(这里是父工作流)完成后,会自动终止所有关联的子工作流
  6. 此时子工作流还在等待第二次Selector.Select(ctx)来处理SignalC,却被提前终止,因此SignalC从未被处理,childReceivedC也始终是false

修复方案

核心修改是让父工作流在发送SignalC后,等待子工作流完全执行完毕再退出,确保子工作流有足够时间处理所有信号。修改后的父工作流代码如下:

parentWorkflow := func(ctx workflow.Context) error {
    cwo := workflow.ChildWorkflowOptions{
        WorkflowID: "child-workflow-id",
    }
    var childWE workflow.Execution
    workflowId := workflow.GetInfo(ctx).WorkflowExecution.ID
    ctx = workflow.WithChildOptions(ctx, cwo)

    // 保存子工作流的Future,用于后续等待子工作流完成
    childFuture := workflow.ExecuteChildWorkflow(ctx, "MockChildWorkflow", workflowId)
    // 获取子工作流的Execution信息
    err := childFuture.GetChildWorkflowExecution().Get(ctx, &childWE)
    if err != nil {
        return err
    }

    workflow.SignalExternalWorkflow(ctx, childWE.ID, childWE.RunID, SignalA, "payload-A")
    fmt.Println("Parent sent signal A")

    var bVal string
    s := workflow.NewSelector(ctx)
    s.AddReceive(workflow.GetSignalChannel(ctx, SignalB), func(c workflow.ReceiveChannel, _ bool) {
        c.Receive(ctx, &bVal)
        fmt.Println("Parent received signal B")
        _ = workflow.SignalExternalWorkflow(ctx, childWE.ID, childWE.RunID, SignalC, "payload-C").Get(ctx, nil)
        fmt.Println("Parent sent signal C")
    })
    s.Select(ctx)

    // 关键:等待子工作流完全执行完毕,再让父工作流退出
    err = childFuture.Get(ctx, nil)
    if err != nil {
        return err
    }

    return nil
}

额外优化建议

除了核心修复,还有两个小细节可以优化测试的可靠性:

  1. 避免使用全局变量:当前代码中的childReceivedC是全局变量,在Temporal测试环境的并发执行场景下容易出现竞态问题。建议通过Temporal测试框架的回调机制或者捕获工作流状态的方式验证信号接收结果,比如使用env.RegisterDelayedCallback或者在工作流中返回状态值。
  2. 简化Selector逻辑:子工作流中的两次Select可以改成循环或者更清晰的等待逻辑,避免因手动计数Select次数导致的遗漏。

修复后的执行流程

修改后整个链路会变成:

  1. 父工作流发送SignalC后,开始等待子工作流完成
  2. 子工作流处理SignalC,设置childReceivedC = true,两次Select执行完成后正常退出
  3. 父工作流收到子工作流完成的通知,自身再退出
  4. 测试环境检测到根工作流和所有子工作流都已完成,测试通过

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 08:53:07