WorkflowStepsModule

PackageFCQRS.Workflows
The workflow builder and the steps a workflow can take.

Summary

NameSignatureSynopsis
workflowworkflow Builds a workflow: `workflow { let!
activityactivity name policy runCalls an external system.
activityAsyncactivityAsync name policy run`activity` for a function that returns an `Async`.
sleepsleep durationWaits for `duration`.
untiluntil instantWaits until `instant`.
nownow The current UTC time, stored so that replay returns the same value.
newGuidnewGuid A new GUID, stored so that replay returns the same value.
randomrandom A random number in [0, 1), stored so that replay returns the same value.
allall branchesRuns the branches together and gives every result, in branch order.
allAtMostallAtMost limit items bodyRuns `body` for every item, at most `limit` at a time, and gives the results in item order.
racerace branchesRuns the branches together.
waitSignalwaitSignal nameWaits for a signal named `name` and gives its payload.
waitSignalForwaitSignalFor name timeoutWaits for a signal named `name` for at most `timeout`, measured from the stored start of the step.
sendWithsendWith policy aggregate aggregateId commandSends a command to an aggregate under `policy` and gives the reply: an event that this command caused.
sendsend aggregate aggregateId command`sendWith` under `Retry.command`: send again when no reply came in time, with backoff, for five minutes.
sendWithFiltersendWithFilter policy filter aggregate aggregateId commandSends 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.
versionversion changeId latestA value that records which version of the workflow's code an instance runs, for changing a workflow while instances are running: let!

workflow

workflow
Member
Builds a workflow: `workflow { let! x = activity ... }`.

Returns

WorkflowBuilder

activity

activity name policy run
Member
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

NameTypeDescription
namestring
policyRetryPolicy
runAttemptContext -> Task<'T>

Returns

Workflow<'T>

activityAsync

activityAsync name policy run
Member
`activity` for a function that returns an `Async`.

Parameters

NameTypeDescription
namestring
policyRetryPolicy
runAttemptContext -> Async<'T>

Returns

Workflow<'T>

sleep

sleep duration
Member
Waits for `duration`. The due time is stored when the step is first reached, so a restart does not postpone it.

Parameters

NameTypeDescription
durationTimeSpan

Returns

Workflow<unit>

until

until instant
Member
Waits until `instant`. A time that names no zone (`DateTimeKind.Unspecified`) is read as UTC, and a local time is converted to UTC.

Parameters

NameTypeDescription
instantDateTime

Returns

Workflow<unit>

now

now
Member
The current UTC time, stored so that replay returns the same value.

Returns

Workflow<DateTime>

newGuid

newGuid
Member
A new GUID, stored so that replay returns the same value.

Returns

Workflow<Guid>

random

random
Member
A random number in [0, 1), stored so that replay returns the same value.

Returns

Workflow<float>

all

all branches
Member
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

NameTypeDescription
branchesWorkflow<'T> list

Returns

Workflow<'T list>

allAtMost

allAtMost limit items body
Member
Runs `body` for every item, at most `limit` at a time, and gives the results in item order.

Parameters

NameTypeDescription
limitint
items'A list
body'A -> Workflow<'T>

Returns

Workflow<'T list>

race

race branches
Member
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

NameTypeDescription
branchesWorkflow<'T> list

Returns

Workflow<'T>

waitSignal

waitSignal name
Member
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

NameTypeDescription
namestring

Returns

Workflow<'T>

waitSignalFor

waitSignalFor name timeout
Member
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

NameTypeDescription
namestring
timeoutTimeSpan

Returns

Workflow<'T option>

sendWith

sendWith policy aggregate aggregateId command
Member
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

NameTypeDescription
policyRetryPolicy
aggregateAggregateHandle<'Command, 'Event>
aggregateIdstring
command'Command

Returns

Workflow<'Event>

send

send aggregate aggregateId command
Member
`sendWith` under `Retry.command`: send again when no reply came in time, with backoff, for five minutes.

Parameters

NameTypeDescription
aggregateAggregateHandle<'Command, 'Event>
aggregateIdstring
command'Command

Returns

Workflow<'Event>

sendWithFilter

sendWithFilter policy filter aggregate aggregateId command
Member
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

NameTypeDescription
policyRetryPolicy
filter'Event -> bool
aggregateAggregateHandle<'Command, 'Event>
aggregateIdstring
command'Command

Returns

Workflow<'Event>

version

version changeId latest
Member
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

NameTypeDescription
changeIdstring
latestint

Returns

Workflow<int>