Skip to content

Commit e57da73

Browse files
Document await signal waits
1 parent 4a642e8 commit e57da73

File tree

9 files changed

+27
-27
lines changed

9 files changed

+27
-27
lines changed

docs/features/concurrency.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import ConcurrencySimulator from '@site/src/components/ConcurrencySimulator';
66

77
# Concurrency
88

9-
In `Workflow\V2`, named workflows use straight-line helpers inside an ordinary `handle()` method: `activity()`, `signal()`, `timer()`, `sideEffect()`, `getVersion()`, and the other single-step helpers suspend directly under the hood instead of forcing `yield` into every workflow body. Named v2 workflows are straight-line only, so do not `yield` from the workflow body.
9+
In `Workflow\V2`, named workflows use straight-line helpers inside an ordinary `handle()` method: `activity()`, `await()`, `timer()`, `sideEffect()`, `getVersion()`, and the other single-step helpers suspend directly under the hood instead of forcing `yield` into every workflow body. Use `await('signal-name')` for one named signal value. Named v2 workflows are straight-line only, so do not `yield` from the workflow body.
1010

1111
Parallel barriers still suspend as one durable workflow step through `all([...])`. In straight-line workflows, build those barriers with closures such as `fn () => activity(...)` and `fn () => child(...)` so the runtime can see the full barrier tree before the workflow suspends. Results still come back in the original nested array shape, while Waterline keeps each durable leaf wait visible and uses `parallel_group_path` to show which outer and inner barriers that leaf belongs to.
1212

@@ -101,7 +101,7 @@ In that example, Waterline exposes three open leaf waits, not one synthetic "nes
101101

102102
## Async Callback
103103

104-
`async(...)` runs a serializable callback as a durable child workflow with the system type `durable-workflow.async`. Async callbacks use the same straight-line-only helper contract as named v2 workflows, so `activity()`, `signal()`, `timer()`, `sideEffect()`, and the other single-step helpers suspend directly inside the callback body without forcing `yield`.
104+
`async(...)` runs a serializable callback as a durable child workflow with the system type `durable-workflow.async`. Async callbacks use the same straight-line-only helper contract as named v2 workflows, so `activity()`, `await()`, `timer()`, `sideEffect()`, and the other single-step helpers suspend directly inside the callback body without forcing `yield`.
105105

106106
```php
107107
use function Workflow\V2\{activity, async};
@@ -125,7 +125,7 @@ final class CustomerWorkflow extends Workflow
125125
}
126126
```
127127

128-
The parent run sees the callback as a child wait, so command history, lineage, and Waterline detail use the same `child_call_id`, child run id, and child outcome history as an explicit `child(...)` call. The callback is serialized with Laravel's serializable-closure support, so keep it app-local and deployment-local. Use a named `child(SomeWorkflow::class, ...)` call when the work needs a stable public workflow type for cross-service routing or long-lived code evolution. `async(...)` callbacks are now straight-line only in v2, so call helpers like `activity()`, `child()`, `signal()`, `timer()`, and `all([...])` directly without `yield`.
128+
The parent run sees the callback as a child wait, so command history, lineage, and Waterline detail use the same `child_call_id`, child run id, and child outcome history as an explicit `child(...)` call. The callback is serialized with Laravel's serializable-closure support, so keep it app-local and deployment-local. Use a named `child(SomeWorkflow::class, ...)` call when the work needs a stable public workflow type for cross-service routing or long-lived code evolution. `async(...)` callbacks are now straight-line only in v2, so call helpers like `activity()`, `child()`, `await()`, `timer()`, and `all([...])` directly without `yield`.
129129

130130
## Mixed Activity + Child Barriers
131131

docs/features/queries.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Queries replay committed history for the current selected run and then invoke th
1515
```php
1616
use Workflow\QueryMethod;
1717
use Workflow\V2\Workflow;
18-
use function Workflow\V2\signal;
18+
use function Workflow\V2\await;
1919

2020
final class ApprovalWorkflow extends Workflow
2121
{
@@ -25,7 +25,7 @@ final class ApprovalWorkflow extends Workflow
2525
{
2626
$this->stage = 'waiting-for-approval';
2727

28-
signal('approved-by');
28+
await('approved-by');
2929

3030
$this->stage = 'approved';
3131
}

docs/features/side-effects.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sidebar_position: 5
77
A side effect is a closure containing non-deterministic code. The closure is only executed once and the result is saved. It will not execute again if the workflow is retried. Instead, it will return the saved result. This makes the workflow deterministic because replaying the workflow will always return the same stored value rather than re-running the non-deterministic code.
88

99
```php
10-
use function Workflow\V2\signal;
10+
use function Workflow\V2\await;
1111
use function Workflow\V2\sideEffect;
1212
use Workflow\V2\Attributes\Signal;
1313
use Workflow\V2\Workflow;
@@ -18,7 +18,7 @@ class MyWorkflow extends Workflow
1818
public function handle(): array
1919
{
2020
$token = sideEffect(fn () => random_int(1000, 9999));
21-
$finish = signal('finish');
21+
$finish = await('finish');
2222

2323
return compact('token', 'finish');
2424
}

docs/features/signal+timer.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ sidebar_position: 4
44

55
# Signal + Timer
66

7-
`Workflow\V2` supports `await($condition, timeout: $seconds, conditionKey: $key)` for timeout-backed condition waits.
7+
`Workflow\V2` supports both `await($condition, timeout: $seconds, conditionKey: $key)` for timeout-backed condition waits and `await('signal-name', timeout: $seconds)` for timeout-backed named signal waits.
88

99
Use it when the workflow should continue as soon as some durable replayed state becomes true, but should also unblock after a deadline if that state never changes.
1010

@@ -68,4 +68,4 @@ $workflow->markReady();
6868

6969
The return value is `true` when the condition becomes true before the timeout task fires and `false` when the timeout wins.
7070

71-
If you want to wait for one named signal value directly instead of waiting for a local predicate, keep using `signal('name')`. `Workflow\V2` does not use legacy `#[SignalMethod]` mutator methods to flip workflow state.
71+
For named signals, `await('name', timeout: minutes(5))` returns the signal payload when the signal arrives and `null` when the timeout wins. `null` is reserved for timeout: no-argument signals resolve to `true`, one argument resolves to that value, and multiple arguments resolve to an array. `Workflow\V2` does not use legacy `#[SignalMethod]` mutator methods to flip workflow state.

docs/features/signals.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ Signals allow you to trigger events in a workflow from outside the workflow. Thi
1010

1111
## Named Signal Waits
1212

13-
A workflow calls `signal('signal-name')` directly. The next accepted signal command with that name resumes the run and returns a deterministic value to the suspended workflow.
13+
A workflow calls `await('signal-name')` directly. The next accepted signal command with that name resumes the run and returns a deterministic value to the suspended workflow.
1414

1515
```php
1616
use Workflow\V2\Attributes\Signal;
1717
use Workflow\V2\Attributes\Type;
1818
use Workflow\V2\Workflow;
19-
use function Workflow\V2\signal;
19+
use function Workflow\V2\await;
2020

2121
#[Type('order-approval')]
2222
#[Signal('approved-by', [
@@ -26,7 +26,7 @@ final class OrderApprovalWorkflow extends Workflow
2626
{
2727
public function handle(): array
2828
{
29-
$approvedBy = signal('approved-by');
29+
$approvedBy = await('approved-by');
3030

3131
return [
3232
'approved_by' => $approvedBy,
@@ -65,7 +65,7 @@ Signal behavior:
6565
- each named wait gets its own durable `signal_wait_id`, and buffered same-name signals keep that same id across `SignalReceived`, `SignalWaitOpened`, and `SignalApplied`
6666
- selected-run detail exposes those lifecycle rows as `signals[*]`, with `id`, `command_id`, `command_sequence`, `workflow_sequence`, `signal_wait_id`, status, outcome, validation errors, and stored arguments
6767
- when a declared signal contract exists, PHP, webhook, and Waterline signal intake all accept either positional arguments or a JSON or associative object of named arguments, and invalid requests reject as `rejected_invalid_arguments` with machine-readable `validation_errors` for missing arguments, unknown arguments, declared type mismatches, or nullability violations
68-
- when a signal has no declared parameter contract, `signal('approved-by')` still receives `true` when no arguments were sent, the single argument when one value was sent, or the full argument array when multiple values were sent; `attemptSignalWithArguments('name', ['key' => 'value'])` keeps treating that associative array as one payload value instead of guessing named arguments
68+
- when a signal has no declared parameter contract, `await('approved-by')` receives `true` when no arguments were sent, the single argument when one value was sent, or the full argument array when multiple values were sent; `attemptSignalWithArguments('name', ['key' => 'value'])` keeps treating that associative array as one payload value instead of guessing named arguments
6969
- before a signal is accepted, Waterline projects the run as `wait_kind = signal` and `liveness_state = waiting_for_signal`, which means it is waiting healthily for external input rather than needing repair
7070
- once a signal command is durably accepted, that external signal wait is resolved; Waterline should then show either the backing workflow task with `workflow_wait_kind = signal`, `workflow_signal_id`, `workflow_command_id`, the open wait id, and the `workflow_signal` resume source, or, if that task disappeared before `SignalApplied`, `repair_needed` with `wait_kind = signal`, `open_wait_id = signal-application:{signal_id}` when the lifecycle row exists, and the same metadata on the repaired task
7171
- repeated waits with the same signal name stay distinguishable in Waterline and the typed timeline through both the workflow step `sequence` and the durable `signal_wait_id`
@@ -90,7 +90,7 @@ The cursor is automatically managed by the engine during signal application and
9090

9191
## Condition Waits
9292

93-
`await($condition, $conditionKey = null)` provides replay-safe condition waits. Use it when the predicate depends only on workflow state that was already derived from durable inputs such as updates, activity results, or child results. If you want one named external signal value directly, prefer `signal('name')`.
93+
`await($condition, $conditionKey = null)` provides replay-safe condition waits. Use it when the predicate depends only on workflow state that was already derived from durable inputs such as updates, activity results, or child results. If you want one named external signal value directly, call `await('name')`.
9494

9595
Condition waits are driven by an update method instead of signal mutators:
9696

docs/features/webhooks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ POST /webhooks/instances/{workflowId}/runs/{runId}/signals/{signal}
606606
}
607607
```
608608

609-
The `arguments` field must be an array. When it is omitted, the signal resumes `signal(...)` with `true`.
609+
The `arguments` field must be an array. When it is omitted, a workflow waiting with `await('signal-name')` resumes with `true`.
610610
The targeted workflow class must also declare the signal name with `#[Workflow\V2\Attributes\Signal('...')]`; undeclared names are rejected durably instead of being buffered blindly.
611611

612612
Signal example:

0 commit comments

Comments
 (0)