Skip to content

wait 声明了超时契约但完全没有实现:onTimeout 零读取者,timeoutMs 被当成定时时长用 —— showcase 自己在依赖它 #4158

Description

@os-zhuang

#4045wait 契约毕业时发现的,属于「已声明但从不被读」那条臂 —— 而且是 PD #10 的形状:宣传了一个运行时不提供的能力。

两处,合起来是一件事

1. waitEventConfig.onTimeout 有零个读取者。

// packages/spec/src/automation/flow.zod.ts:210
onTimeout: z.enum(['fail', 'continue']).default('fail').describe('Behavior when the wait times out'),

在 framework 仓库里搜 onTimeout(排除 dist/.d.ts、测试),除定义处外的命中全是无关的:acquireConnectionTimeout 注释、actionTimeoutMsconnectionTimeoutMs。没有任何路径读它。它带 .default('fail'),所以每个 wait 节点都被盖上一个不起作用的值。

2. waitEventConfig.timeoutMs 唯一的读取者把它当别的东西用。

声明的语义是超时上限:

// flow.zod.ts:209
timeoutMs: z.number().int().min(0).optional().describe('Maximum wait time before timeout (ms)'),

而唯一读它的地方把它当定时时长的兜底

// packages/services/service-automation/src/builtin/wait-node.ts
const durationMs =
  parseIsoDuration(wec.timerDuration) ??
  (typeof wec.timeoutMs === 'number' ? wec.timeoutMs : undefined);

即:没写 timerDuration 时,timeoutMs 变成了「等多久」,而不是「最多等多久」。(engine.ts:3135 读的 node.timeoutMs 是节点上的另一个字段,不是这个。)

合起来:wait 根本没有超时实现。 Zod 和文档描述的「等待超时后 fail 或 continue」这套契约在运行时不存在。

为什么这条值得单独立项

我们自己的示例在依赖它。

// examples/app-showcase/src/automation/flows/index.ts:554
waitEventConfig: { eventType: 'timer', timerDuration: 'PT1M', onTimeout: 'continue' },

onTimeout: 'continue' 什么都不做。而且 timeoutMs 进了生成参考文档(content/docs/references/automation/flow.mdx:107waitEventConfig 类型里列着 timeoutMs?: integer),所以这是已发布的表面,不是内部细节。

两条路,需要人来定

不是可以顺手猜的 —— 两条都会改动已发布契约:

A. 实现它。 在 resume 触发器之外再排一个一次性超时 job:到点后 resume(runId) 并按 onTimeout 决定是让该节点失败还是继续往下走。要注意冷启动重排那一遍(rearmSuspendedWaitTimers)也得认识这个第二个 deadline,否则重启后超时就丢了 —— 这正是 ADR-0019 后续为定时器补 waitUntil 持久化时踩过的那类问题。同时得把 timeoutMs 从「时长兜底」改回「超时上限」,那是一个行为变更:今天只写 timeoutMs 的流程会从「等 N 毫秒」变成「立刻不带 deadline 挂起」。

B. 撤回它。 给两个键上墓碑、停止发布,并把 showcase 那处 onTimeout 删掉。如果 timeoutMs 的实际用法就是「时长」,那更诚实的做法是把它并进 timerDurationparseIsoDuration 已经接受裸数字当毫秒,所以 timerDuration: 60000 已经能表达同一件事)。

我倾向 B 的后半段timerDuration 已经能表达 timeoutMs 今天实际做的事,而真正的超时语义是个新特性,应该在有人真的要它的时候按需求做,而不是为了对齐一段没人实现过的描述文字去补。但这条要你拍。

相关

未覆盖

只搜了 framework 仓库。objectui 侧是否有读 onTimeout 的设计器代码没查 —— 但本仓库里没找到 waitEventConfig 的任何设计器表单,所以大概率也没有。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions