Header menu logo FCQRS

Read your writes

After you send a command you often want to read the result back — render the page that shows the thing you just created. But the read model is updated by a projection that runs slightly after the command is acknowledged, so a naive "send, then read" can read a stale model. Read-your-writes means: wait until the projection has processed your event, then read.

One call

Fcqrs.sendAwaiting does the whole dance safely: it subscribes on the correlation id before sending (the ordering that makes the wait race-free), sends, and awaits the projection — only if the ack was journaled:

let subs = Fcqrs.projection api (Projection.single 0 handle)   // the ISubscribe stream

let! ack =
    Fcqrs.sendAwaiting subs documents cid id (CreateOrUpdate doc) (function
        | Document.Updated _ -> true
        | _ -> false)
// on return, the read model already reflects the write — read it now

Why "only if journaled"

An aggregate can answer a command two ways: it can persist an event (which flows to the journal and then the projection), or it can defer one — a rejection, or an idempotent no-op — which is delivered to you but never journaled, so the projection will never see it. Both arrive as the same Event shape, so a caller cannot tell them apart by looking at the payload.

FCQRS stamps the delivered envelope with Event.Journaled : bool optionSome true for a journaled ack, Some false for a deferred one, None for an envelope that never passed aggregate delivery. sendAwaiting reads it and skips the wait on a deferred ack, so a rejection returns immediately instead of hanging on a projection event that will never arrive.

If you are composing the wait by hand, subscribe before you send, and gate the await on ack.Journaled <> Some false.

val subs: obj
val id: x: 'T -> 'T

Type something to start searching.