Skip to content

Declarative retry and backoff policies for action nodes (#86) - #225

Open
EricWittmann wants to merge 19 commits into
mainfrom
i86
Open

EricWittmann wants to merge 19 commits into
mainfrom
i86

Conversation

@EricWittmann

Copy link
Copy Markdown
Contributor

Closes #86

Summary

Lets workflow authors declare retry and backoff policies on action nodes, with a workflow-level default,
instead of relying on the fixed engine policy (immediate retries, limit of 10).

  • Definition: action nodes take config.retry with maxAttempts, delay, backoff
    (fixed|exponential), multiplier, maxDelay and jitter. A workflow can set defaults.retry.
    A node's policy replaces the default entirely; fields are not merged.
  • Engine: the WorkflowErrorHandler still decides whether to retry; the policy decides how many times
    and when. A zero delay retries immediately. A positive delay parks the node and records retryAt on the
    open history entry. Attempt counts live on that entry (attempt), so they survive async PENDING
    resumes and persistence.
  • Host API: getPendingRetries(instance) lists parked retries; call retryNode(workflow, instance, nodeId) when your timer fires. retryNode does nothing for late, duplicate or cancelled timers.
    completeNode throws for a node waiting to retry, and getActionInfo returns null for it.
  • Handlers: they receive the attempt number and the effective policy through a new optional
    handleError(..., RetryContext) overload. Existing handlers are unaffected.
  • Validation: Java and TypeScript report the same codes (INVALID_RETRY_*, plus a
    RETRY_ON_NON_ACTION_NODE warning). Both run against a shared fixture,
    conformance/retry-validation.json, and the schema is updated.
  • UI: a Retry section on action nodes and a "Workflow defaults" section when nothing is selected. Action
    nodes show a ↻N badge. The viewer shows "Retry N/M scheduled at …" for a node waiting to retry.
  • Docs: error handling, typed configuration, the workflow model, contracts and validation.

Backward compatibility

Definitions without a policy behave exactly as before: immediate retries, a limit of 10 and the same
failure message. New fields are optional and omitted from JSON when absent, and the old constructors are
kept. Callers that destructure Workflow or HistoryEntry with Java record patterns will need updating,
because both records gain components.

Testing

  • Engine (mvn test, 730 passing): inline and parked retries, exhaustion, workflow default vs node
    override, exponential backoff, jitter, attempt counts across async resumes, parallel fork/join retries,
    cancel, and late timers.
  • UI (vitest, 970 passing): validator parity with the shared fixture, retry helpers, the editor
    command and fields, and badges. tsc, lint, build and mkdocs build --strict all pass.
  • Manual: checked in the dev app editor: badges, the defaults section, the inherited-policy hint,
    exponential backoff with a decimal multiplier, and validation errors. The viewer's scheduled-retry status
    is covered by unit tests only, because none of the demo scenarios has an instance waiting on a retry.

Follow-ups (not in this PR)

  • Group workflow-default edits into one undo step.
  • Format retryAt for people in the viewer.
  • Optionally notify listeners when a retry is scheduled.

Design spec: docs/superpowers/specs/2026-10-21-declarative-retry-policy-design.md

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Declarative retry and backoff policies for action nodes

1 participant