WorkflowStepsModule
PackageFCQRS.Workflows
The workflow builder and the steps a workflow can take.
Summary
| Name | Signature | Synopsis |
|---|---|---|
| workflow | workflow | Builds a workflow: `workflow { let! |
| activity | activity name policy run | Calls an external system. |
| activityAsync | activityAsync name policy run | `activity` for a function that returns an `Async`. |
| sleep | sleep duration | Waits for `duration`. |
| until | until instant | Waits until `instant`. |
| now | now | The current UTC time, stored so that replay returns the same value. |
| newGuid | newGuid | A new GUID, stored so that replay returns the same value. |
| random | random | A random number in [0, 1), stored so that replay returns the same value. |
| all | all branches | Runs the branches together and gives every result, in branch order. |
| allAtMost | allAtMost limit items body | Runs `body` for every item, at most `limit` at a time, and gives the results in item order. |
| race | race branches | Runs the branches together. |
| waitSignal | waitSignal name | Waits for a signal named `name` and gives its payload. |
| waitSignalFor | waitSignalFor name timeout | Waits for a signal named `name` for at most `timeout`, measured from the stored start of the step. |
| sendWith | sendWith policy aggregate aggregateId command | Sends a command to an aggregate under `policy` and gives the reply: an event that this command caused. |
| send | send aggregate aggregateId command | `sendWith` under `Retry.command`: send again when no reply came in time, with backoff, for five minutes. |
| sendWithFilter | sendWithFilter policy filter aggregate aggregateId command | Sends a command to an aggregate under `policy` and gives the first event that `filter` accepts, among the events the aggregate publishes under the step's correlation ID. |
| version | version changeId latest | A value that records which version of the workflow's code an instance runs, for changing a workflow while instances are running: let! |
Builds a workflow: `workflow { let! x = activity ... }`.
Returns
WorkflowBuilder
Calls an external system. The call runs at least once: a crash after the call and before
its result is stored repeats it, so pass `IdempotencyKey` to the external system.
`name` is stored and must not change while instances are running.
Parameters
| Name | Type | Description |
|---|---|---|
| name | string | |
| policy | RetryPolicy | |
| run | AttemptContext -> Task<'T> |
Returns
Workflow<'T>
`activity` for a function that returns an `Async`.
Parameters
| Name | Type | Description |
|---|---|---|
| name | string | |
| policy | RetryPolicy | |
| run | AttemptContext -> Async<'T> |
Returns
Workflow<'T>
Waits for `duration`. The due time is stored when the step is first reached, so a restart
does not postpone it.
Parameters
| Name | Type | Description |
|---|---|---|
| duration | TimeSpan |
Returns
Workflow<unit>
Waits until `instant`. A time that names no zone (`DateTimeKind.Unspecified`) is read as
UTC, and a local time is converted to UTC.
Parameters
| Name | Type | Description |
|---|---|---|
| instant | DateTime |
Returns
Workflow<unit>
The current UTC time, stored so that replay returns the same value.
Returns
Workflow<DateTime>
A new GUID, stored so that replay returns the same value.
Returns
Workflow<Guid>
A random number in [0, 1), stored so that replay returns the same value.
Returns
Workflow<float>
Runs the branches together and gives every result, in branch order. If a branch fails,
the others are abandoned and the failure is raised here.
Every branch result is stored in this workflow's journal, so use a child workflow per
item for a fan-out over thousands of items.
Parameters
| Name | Type | Description |
|---|---|---|
| branches | Workflow<'T> list |
Returns
Workflow<'T list>
Runs `body` for every item, at most `limit` at a time, and gives the results in item order.
Parameters
| Name | Type | Description |
|---|---|---|
| limit | int | |
| items | 'A list | |
| body | 'A -> Workflow<'T> |
Returns
Workflow<'T list>
Runs the branches together. The first to finish decides the result, with its value or
its exception, and the others are abandoned. The winner is stored, so replay selects
the same branch.
Parameters
| Name | Type | Description |
|---|---|---|
| branches | Workflow<'T> list |
Returns
Workflow<'T>
Waits for a signal named `name` and gives its payload. A signal that arrived before the
workflow reached this step was stored and is consumed here; signals with one name are
consumed oldest first.
Parameters
| Name | Type | Description |
|---|---|---|
| name | string |
Returns
Workflow<'T>
Waits for a signal named `name` for at most `timeout`, measured from the stored start of
the step. Gives `None` when the time passes first; a signal that arrives later stays
stored for the next wait.
Parameters
| Name | Type | Description |
|---|---|---|
| name | string | |
| timeout | TimeSpan |
Returns
Workflow<'T option>
Sends a command to an aggregate under `policy` and gives the reply: an event that this
command caused. An event that another command caused under the same correlation ID, such
as a command of the saga this one started, is not taken.
The workflow subscribes to the aggregate's replies before it sends. Every send of the step
carries the same correlation ID and the same command ID, so the reply to an earlier send
still answers the step. One send waits for the policy's `AttemptTimeout`, or for
`akka.fcqrs.command-timeout` when the policy sets none, and then the command is sent again.
After a restart the command is sent again unless its reply was stored, so the aggregate
must answer a repeated command with the same verdict.
When the policy runs out, the step fails as `OutcomeUnknown`: the command may have been
applied.
Parameters
| Name | Type | Description |
|---|---|---|
| policy | RetryPolicy | |
| aggregate | AggregateHandle<'Command, 'Event> | |
| aggregateId | string | |
| command | 'Command |
Returns
Workflow<'Event>
`sendWith` under `Retry.command`: send again when no reply came in time, with backoff, for
five minutes.
Parameters
| Name | Type | Description |
|---|---|---|
| aggregate | AggregateHandle<'Command, 'Event> | |
| aggregateId | string | |
| command | 'Command |
Returns
Workflow<'Event>
Sends a command to an aggregate under `policy` and gives the first event that `filter`
accepts, among the events the aggregate publishes under the step's correlation ID. The
event need not be the reply to this command: a saga's commands carry the correlation ID
of the command that started the saga, so the step can wait for an event the saga caused.
The wait is in memory. An event published while no attempt listens, for example during a
restart, is not seen. Each attempt listens for the policy's `AttemptTimeout`, or for
`akka.fcqrs.command-timeout` when the policy sets none, and then the command is sent again,
so the aggregate must answer a repeated command with an event the filter accepts once the
outcome is known. Wait for a signal when the event must not be missed. `filter` must
depend on the event alone. The step is stored as `send` stores its step, so one can
replace the other in a workflow that is running.
Parameters
| Name | Type | Description |
|---|---|---|
| policy | RetryPolicy | |
| filter | 'Event -> bool | |
| aggregate | AggregateHandle<'Command, 'Event> | |
| aggregateId | string | |
| command | 'Command |
Returns
Workflow<'Event>
A value that records which version of the workflow's code an instance runs, for changing
a workflow while instances are running:
let! v = version "add-fraud-check" 2
if v >= 2 then ... new steps ... else ... the steps as they were ...
A new instance stores `latest` and gets it. An instance that had already passed this
point when the change was deployed gets 1 and stores nothing. The step takes no place
in the step sequence, so adding it does not move the steps after it.
`changeId` names the change. The number is stored under the step's position and this
name. One name may appear at different positions, such as once per round of a loop, and
different names may share a position. The same name twice at one position is not allowed.
A later change at the same point keeps the name and raises `latest`. The name is a
persistent contract: after a rename, an instance that stored a number finds none under the
new name and gets 1.
Parameters
| Name | Type | Description |
|---|---|---|
| changeId | string | |
| latest | int |
Returns
Workflow<int>