FSharpModule
PackageFCQRS
Idiomatic-F# functional facade for FCQRS.
Gives F# consumers the same one-call ergonomics the C# host-builder
(HostExtensions.fs) gives C#, but with F# idioms: records-of-functions for the
definitions, typed handles for the results, an explicit wiring pipeline, and
plain helpers for saga side effects. It is a *pure addition* that wraps only the
existing primitives (IActor.InitializeActor / SagaBuilder.initSimple / Projections.startTracked
/ InitializeSagaStarter / CreateCommandSubscription / Actor.api) and changes
nothing in the C# interop layer or the core.
open FCQRS.FSharp
let api = Fcqrs.actor config loggerFactory (Some (Fcqrs.connect DBType.Sqlite conn)) "Cluster"
let documents = Fcqrs.aggregate api { Name="Document"; Initial=...; Decide=...; Fold=... }
let slugs = Fcqrs.aggregate api { Name="Slug"; Initial=...; Decide=...; Fold=... }
let publication = Fcqrs.saga api (publicationDef documents.Factory slugs.Factory)
Fcqrs.wireSagaStarters api [ publication ]
let subs = Fcqrs.projection api (Projection.single 0 updateReadModel)
// (Projection.multi when you must control which notifications publish)
// send a command and await the matching aggregate reply:
let! ev = documents.Send (Fcqrs.newCid()) (Fcqrs.aggregateId id) cmd (fun e -> ...)
Summary
| Name | Signature | Synopsis |
|---|---|---|
| toOriginator | toOriginator factory command | Send a command back to the saga's originator aggregate. |
| toAggregate | toAggregate factory id command | Send a command to a specific aggregate instance by id (cross-aggregate). |
| toActor | toActor actorRef command | Send a command to a concrete actor ref. |
| toSelf | toSelf command | Send a command to the saga itself (raw, lands in HandleEvent), for example a timeout. |
| toOriginatorAfter | toOriginatorAfter factory delayMs taskName command | Delayed variant of toOriginator (delayMs, taskName key). |
| toAggregateAfter | toAggregateAfter factory id delayMs taskName command | Delayed variant of toAggregate. |
| toActorAfter | toActorAfter actorRef delayMs taskName command | Delayed variant of toActor. |
| toSelfAfter | toSelfAfter delayMs taskName command | Schedule a message to the saga itself after a delay, the idiomatic saga timeout: enter a state, toSelfAfter a reminder, and HandleEvent decides whether it still matters when it arrives. |
| expecting | expecting deadline retryEvery resend | Declare a saga expectation: stay in this state, send `resend` now, re-send exactly those commands on `retryEvery`, and once `deadline` (measured from the persisted state-entry time, so restarts cannot postpone it) has passed without a state transition, deliver an ExpectationExhausted message to HandleEvent. |
| journalType | journalType name | A (type, stable-journal-name) pair for Fcqrs.journalTypes. |
| persist | persist event | No description available. |
| persistAll | persistAll events | No description available. |
| persistAndSnapshot | persistAndSnapshot event | No description available. |
| defer | defer event | Publish and fold the event without journaling it. |
| persistIf | persistIf shouldPersist event | Persist the event when `shouldPersist`, else defer it (published and folded but not journalled). |
| transitionTo | transitionTo state | No description available. |
| dispatch | dispatch description | Dispatch an async side effect (a "mini saga" without persistence) by its DATA description. |
| total | total onError work | Make an effect-runner body TOTAL: run `work`, mapping ANY exception (oracle error, timeout, cancellation) to a command via `onError`, so the runner never lets an exception escape (which would fail-fast the process). |
| stay | stay | No description available. |
| stop | stop | No description available. |
| nextState | nextState state | No description available. |
Send a command back to the saga's originator aggregate.
Parameters
| Name | Type | Description |
|---|---|---|
| factory | AggregateFactory | |
| command | obj |
Returns
ExecuteCommand
Send a command to a specific aggregate instance by id (cross-aggregate).
Parameters
| Name | Type | Description |
|---|---|---|
| factory | AggregateFactory | |
| id | string | |
| command | obj |
Returns
ExecuteCommand
Send a command to a concrete actor ref.
Parameters
| Name | Type | Description |
|---|---|---|
| actorRef | IActorRef<obj> | |
| command | obj |
Returns
ExecuteCommand
Send a command to the saga itself (raw, lands in HandleEvent), for example a timeout.
Parameters
| Name | Type | Description |
|---|---|---|
| command | obj |
Returns
ExecuteCommand
Delayed variant of toOriginator (delayMs, taskName key).
Parameters
| Name | Type | Description |
|---|---|---|
| factory | AggregateFactory | |
| delayMs | int64 | |
| taskName | string | |
| command | obj |
Returns
ExecuteCommand
Delayed variant of toAggregate.
Parameters
| Name | Type | Description |
|---|---|---|
| factory | AggregateFactory | |
| id | string | |
| delayMs | int64 | |
| taskName | string | |
| command | obj |
Returns
ExecuteCommand
Delayed variant of toActor.
Parameters
| Name | Type | Description |
|---|---|---|
| actorRef | IActorRef<obj> | |
| delayMs | int64 | |
| taskName | string | |
| command | obj |
Returns
ExecuteCommand
Schedule a message to the saga itself after a delay, the idiomatic saga
timeout: enter a state, toSelfAfter a reminder, and HandleEvent decides
whether it still matters when it arrives.
Parameters
| Name | Type | Description |
|---|---|---|
| delayMs | int64 | |
| taskName | string | |
| command | obj |
Returns
ExecuteCommand
Declare a saga expectation: stay in this state, send `resend` now, re-send
exactly those commands on `retryEvery`, and once `deadline` (measured from
the persisted state-entry time, so restarts cannot postpone it) has passed
without a state transition, deliver an ExpectationExhausted message to
HandleEvent. The handler must answer it with a transition, typically to a
failure or compensation state. Resend commands must be retry-safe and must
not carry their own DelayInMs.
Parameters
| Name | Type | Description |
|---|---|---|
| deadline | TimeSpan | |
| retryEvery | RetrySchedule | |
| resend | ExecuteCommand list |
Returns
SagaTransition<'State>
A (type, stable-journal-name) pair for Fcqrs.journalTypes.
Parameters
| Name | Type | Description |
|---|---|---|
| name | string |
Returns
Type * string
Parameters
| Name | Type | Description |
|---|---|---|
| event | 'e |
Returns
EventAction<'e>
Publish and fold the event without journaling it. A deferred event does not
start a saga; running sagas still receive it.
Parameters
| Name | Type | Description |
|---|---|---|
| event | 'e |
Returns
EventAction<'e>
Persist the event when `shouldPersist`, else defer it (published and folded
but not journalled). The deferred fold should preserve state, because it
cannot be replayed, and the deferred event does not start a saga. This is the
idempotent "emit this verdict, write it only once" shape.
Parameters
| Name | Type | Description |
|---|---|---|
| shouldPersist | bool | |
| event | 'e |
Returns
EventAction<'e>
Parameters
| Name | Type | Description |
|---|---|---|
| state | 'state |
Returns
EventAction<'state>
Dispatch an async side effect (a "mini saga" without persistence) by its
DATA description. `decide` stays pure and inspectable;
`decide cmd state = dispatch (ClusterThemes texts)` holds by structural
equality, and the oracle lives in the runner registered at
`Fcqrs.aggregateWithEffects`. EPHEMERAL: the in-flight work is not
journaled; use a saga when the result must survive a crash. See
`EventAction.RunAsync`.
Parameters
| Name | Type | Description |
|---|---|---|
| description | 'description |
Returns
EventAction<'event>
Make an effect-runner body TOTAL: run `work`, mapping ANY exception (oracle
error, timeout, cancellation) to a command via `onError`, so the runner
never lets an exception escape (which would fail-fast the process).
Parameters
| Name | Type | Description |
|---|---|---|
| onError | exn -> 'command | |
| work | Async<'command> |
Returns
Async<'command>