Uber Cadence工作流异常:270小时计时器与UNHANDLED_DECISION错误求助
Uber Cadence 新手问题解答
一、计时器来源与UNHANDLED_DECISION错误解析
计时器来源排查
你遇到的270小时超长计时器,基本是代码中Workflow.sleep生成的,重点排查两段代码的配置或逻辑:
- 第一段代码中,若
LocalDateTime.now()未指定时区,与myWorkflow.getStartDateTime()的UTC时区不匹配,可能计算出异常时长; - 第二段代码中,若
props里的waitPeriod数值配置错误(比如误填270)、或waitPeriodType单位选错(比如把分钟设为小时),会直接生成对应时长的计时器。
UNHANDLED_DECISION错误原因
这个错误本质是工作流非确定性导致的,Cadence要求工作流代码必须保证重放时的行为一致,常见触发场景:
- 工作流代码修改后,旧工作流重放时,新代码的决策逻辑与历史记录不匹配;
- 代码中使用了非确定性API(比如未指定时区的
LocalDateTime.now()),重放时该值变化,导致Timer事件无法匹配对应生成逻辑,触发堆栈中的NonDeterminisicWorkflowError。
二、批量终止工作流的方法
1. Cadence Web UI操作
进入对应Domain的工作流列表页面,通过筛选条件(工作流类型、运行状态等)定位目标工作流,勾选后执行批量终止操作。若工作流数量过大,UI可能存在性能瓶颈,建议用CLI。
2. Cadence CLI批量处理
使用cadence workflow terminate命令结合查询条件批量终止,示例:
# 终止指定Domain下、指定类型的所有运行中工作流 cadence workflow terminate --domain your-domain --query "WorkflowType='YourWorkflowType' AND ExecutionStatus='RUNNING'" --reason "修复非确定性错误"
可通过Cadence查询语法设置更精准的筛选条件(如按启动时间范围过滤)。
三、代码正确性分析与修正
第一段代码(等待到未来启动时间)
原代码存在两个核心问题:
LocalDateTime.now()未指定时区,与UTC时区的startDateTime计算时差时会出错;- 直接使用系统时间API违反工作流确定性要求,重放时会导致行为不一致。
修正后的代码:
// 工作流中必须用Workflow.currentTimeMillis()获取时间,保证重放一致性 Instant now = Instant.ofEpochMilli(Workflow.currentTimeMillis()); Instant startInstant = myWorkflow.getStartDateTime().atZone(CampaignConstants.ZONE_ID_UTC).toInstant(); if (now.isBefore(startInstant)) { Duration waitDuration = Duration.between(now, startInstant); Workflow.sleep(waitDuration); }
第二段代码(按指定时长等待)
原代码缺乏参数校验,易因非法配置生成超长计时器,且无异常处理逻辑。
修正后的代码:
try { String waitPeriodStr = (String) props.get("waitPeriod"); String waitPeriodTypeStr = (String) props.get("waitPeriodType"); if (waitPeriodStr == null || waitPeriodTypeStr == null) { throw new IllegalArgumentException("waitPeriod或waitPeriodType参数缺失"); } Integer waitPeriod = Integer.parseInt(waitPeriodStr); ChronoUnit chronoUnit = ChronoUnit.valueOf(waitPeriodTypeStr.toUpperCase()); // 校验时长合理性,避免生成超长计时器(可根据业务调整限制值) Duration waitDuration = Duration.of(waitPeriod, chronoUnit); if (waitDuration.toHours() > 24) { throw new IllegalArgumentException("等待时长超过最大限制(24小时)"); } Workflow.sleep(waitDuration); } catch (NumberFormatException | IllegalArgumentException e) { Workflow.getLogger(getClass()).error("等待参数配置无效", e); throw new RuntimeException("等待参数错误", e); }
内容的提问来源于stack exchange,提问作者siva
相关产品推荐
相关产品推荐

