Documentation for a newer release is available. View Latest

How Can I Maintain End-to-End Causal Ordering of Domain Events in a Payment Journey?

Being able to determine the causal order of events in a distributed computer system is crucial when building read-side projections of a unit of work based on the domain events of its constituent flows. The DSL provides this functionality out-of-the-box by exchanging an EventId whenever flows communicate with one another as part of a payment journey.

The EventId contains the Lamport timestamp of the flow in which it was first created (the calling flow). When the EventId is passed onto another flow (the called flow), this flow continues to increment the timestamp as required. By passing along an EventId from one flow to another, we enable domain events - belonging to different flows within a single logical unit of work - to be ordered in a causal, happened-before order.

Every generated Action in flo-lang provides access to the current EventId via its getCurrentEventId method, and every Input.Builder provides a withCausedByEventId that can be used to pass along the EventId of the collaborating flow:

@Override
public CompletionStage<Void> execute(SampleExternalDomainAction action) {
    var externalDomainDto = convertToExternalDomain(action);
    return AnotherDomain.appropriateDomain().handle(new AppropriateDomainResponseInput
                .Builder(id, AppropriateDomainResponseCodes.OK)
                .withCausedByEventId(action.getCurrentEventId())
                .build());
}

Without EventIds and their Lamport timestamps, projections would be forced to use system clock timestamps in their stead. As different nodes or processes are typically not perfectly synchronised, clock skew would likely occur, resulting in non-sequential event order.

IMPORTANT]

As mentioned above, the DSL provides this functionality out-of-the-box and no manual work is required to ensure end-to-end causal ordering of domain events in a payment journey.