Skip to content

feat(automation): implement the wait node executor (durable timer/signal pause) - #1469

Merged
xuyushun441-sys merged 1 commit into
mainfrom
feat/wait-node-executor
Jun 1, 2026
Merged

feat(automation): implement the wait node executor (durable timer/signal pause)#1469
xuyushun441-sys merged 1 commit into
mainfrom
feat/wait-node-executor

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

What

The flow designer offered a wait node, but the engine had no executor for it — so a flow using wait couldn't actually run (it would hit "no executor for type 'wait'"). This implements it as a built-in node.

waitsuspends the run on entry (ADR-0019 durable pause — the same suspend/resume machinery as screen / approval, reading the engine-injected $runId), and resumes by one of two paths per waitEventConfig.eventType:

  • timer — schedules a one-shot job (IJobService, { type: 'once', at }) that calls engine.resume(runId) when the ISO-8601 timerDuration elapses. With no job service, the run still suspends and is resumable via an external resume(runId) (logged) — it never silently no-ops or fails the flow (matches the platform's degrade-don't-crash convention).
  • signal / webhook / manual / condition — suspends with the signal name as the correlation key; an external producer resumes when the event arrives.

Adds a parseIsoDuration helper (PT1H, P3D, PT90M, P1DT12H, bare ms). A bare AutomationServicePlugin now installs 13 executors including wait.

Why

First of the "designer can draw it, engine can't run it" gaps (the others: subflow, boundary_event, parallel_gateway/join_gateway). Implementing the executors makes the designer's node palette honest and the showcase examples runnable + testable. wait is the highest-value + most tractable (reuses existing suspend/resume).

Tests

builtin/wait-node.test.ts:

  • parseIsoDuration (ISO durations, bare ms, unparseable/non-positive → undefined)
  • suspend on entry → resume(runId) continues traversal downstream
  • timer: schedules one { type: 'once' } job ~duration out; firing its handler resumes the run + cancels the one-shot
  • named signal: suspends with the signal as correlation, resumes

@objectstack/service-automation113 passing. Worked example showcase_task_follow_up (wait → notify) added to the showcase; showcase suite green.

🤖 Generated with Claude Code

…ignal pause)
The designer offered a `wait` node but the engine had no executor, so flows
using it couldn't run. Implement it as a built-in:
- Suspends the run on entry (ADR-0019 durable pause — same suspend/resume
machinery as screen/approval; reads `$runId` like the approval node).
- timer → schedules a one-shot job (IJobService `{type:'once', at}`) that calls
`engine.resume(runId)` after the ISO-8601 `timerDuration`. No job service →
still suspends, resumable via external resume(runId) (logged, never no-ops).
- signal/webhook/manual/condition → suspends with the signal name as the
correlation key; an external producer resumes.
- Adds `parseIsoDuration` (PT1H/P3D/PT90M/P1DT12H/bare-ms).
A bare AutomationServicePlugin now ships 13 executors incl. `wait`.
Tests: wait-node.test.ts (parsing, suspend→resume traversal, one-shot
job-driven resume, signal suspend) — service-automation 113 passing.
Worked example: showcase_task_follow_up (wait → notify).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercelBot commented Jun 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJun 1, 2026 1:41pm

Request Review

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@xuyushun441-sys@os-zhuang