Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/async-step-completed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@workflow/core': minor
---

Add opt-in `WORKFLOW_ASYNC_STEP_COMPLETED=1`: defer a single sequential inline step's `step_completed` write so the next replay iteration (and, under optimistic start, the next step's body) overlaps it, with all subsequent durable writes and the queue ack ordered behind the deferred write. Only engages with no open hook or wait, on turbo's first delivery — the one case where no concurrent orchestrator invocation can exist.
5 changes: 5 additions & 0 deletions .changeset/inline-delta-turbo-unlocks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@workflow/core': patch
---

Keep the inline event-log delta fast path active with open hooks when `WORKFLOW_PRECONDITION_GUARD=1` and the World declares `capabilities.preconditionGuard`. The lazy inline `step_started` claim now carries the guard snapshot so a stale replay's claim is fenced (412 → fresh replay), and guard-enforced batches with an open hook take the await-then-run path so a fenced claim never executes the step body.
6 changes: 6 additions & 0 deletions .changeset/world-capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@workflow/world': minor
'@workflow/world-vercel': patch
---

Add an optional `capabilities?: WorldCapabilities` field to the World interface so implementations can declare backend feature support (`preconditionGuard`, `maxConcurrency`) instead of the runtime inferring it from environment variables; the Vercel World declares both.
12 changes: 11 additions & 1 deletion docs/content/docs/v5/configuration/runtime-tuning.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ For example, a workflow can run a 10-minute inline step even with `WORKFLOW_REPL
- Default: disabled
- Set `1` to enable an optimistic-concurrency guard for event creation: replay-context event creations send a `stateUpdatedAt` snapshot timestamp, and a backend that supports the guard rejects a creation with 412 ([`PreconditionFailedError`](/docs/api-reference/workflow-errors/precondition-failed-error)) when a newer out-of-band event (a received hook or a completed step) was recorded after that snapshot.
- On rejection the runtime reloads the event log and retries, falling back to a queue re-invocation with a fresh replay if it cannot catch up.
- Backends that do not support the guard ignore the snapshot.
- When enabled — and the World declares that it enforces the guard (`capabilities.preconditionGuard`; the Vercel World does) — the runtime also keeps the per-step event-log delta optimization (consuming the delta returned by a step's terminal write instead of issuing an extra `events.list` per step) active while the run has an open hook. Without an enforced guard, an open hook disables it.
- While a hook is open on a guard-enforcing deployment, inline steps take the await-then-run path even when optimistic inline start is enabled: the step's `step_started` claim carries the snapshot and is awaited before the body runs, so a claim the backend rejects as stale never executes user code.
- Backends that do not support the guard ignore the snapshot; they must not declare the capability, so guard-dependent optimizations stay off against them even when the flag is set.

## Inline execution

Expand All @@ -63,6 +65,7 @@ For example, a workflow can run a 10-minute inline step even with `WORKFLOW_REPL

- Default: enabled
- Fast path for a run's first delivery.
- Stops forcing optimistic inline step start once the run creates a hook or wait.
- Set `0` or `false` to disable.

### `WORKFLOW_OPTIMISTIC_INLINE_START`
Expand All @@ -72,6 +75,13 @@ For example, a workflow can run a 10-minute inline step even with `WORKFLOW_REPL
- Use only when step side effects are idempotent.
- Set `0` or `false` to force it off, including the first-delivery fast path used by `WORKFLOW_TURBO`.

### `WORKFLOW_ASYNC_STEP_COMPLETED`

- Default: disabled
- Set `1` to let the runtime defer an inline step's `step_completed` write: the next replay iteration runs on locally-synthesized events (and, with optimistic start active, the next step's body starts) while the write settles in the background. Every subsequent durable write is chained behind the deferred write, and the queue message is only acknowledged after it settles.
- Only engages for a single sequential inline step with no open hook or wait, and only on turbo's first delivery — the one case where no concurrent orchestrator invocation can exist.
- Requires idempotent step side effects, more strongly than `WORKFLOW_OPTIMISTIC_INLINE_START`: a crash while the write is in flight re-executes the step on redelivery, which can produce a different result than the one the next step's body already consumed.

### `WORKFLOW_INLINE_OWNERSHIP`

- Default: enabled
Expand Down
Loading
Loading