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.

wait suspends 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-automation 113 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
Copy link
Copy Markdown

vercel Bot commented Jun 1, 2026

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 1, 2026 1:41pm

Request Review

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

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants