Positions and Ordering
Every committed event has a durable position. Positions are how Orisun expresses ordering, optimistic concurrency, and read paging. Understanding them makes the rest of the API predictable.
The position pair
A position has two fields:
| Field | Backed by | Meaning |
|---|---|---|
commit_position | transaction_id | Groups events committed together. Every event saved in one SaveEvents batch shares the same commit_position. |
prepare_position | global_id | The per-boundary monotonic sequence of the individual event. Unique and strictly increasing within a boundary. |
Ordering within a boundary is the tuple (commit_position, prepare_position), ascending. Positions are per boundary — they are not comparable across boundaries.
The before-first position
Use {-1, -1} to mean "before any event exists":
{"commit_position": -1, "prepare_position": -1}
- As
expected_positioninSaveEvents, it asserts the consistency context is still empty. - As
from_positioninGetEventsorafter_positionin a subscription, it means "start from the very beginning".
Batch semantics
SaveEvents is atomic. For a batch of N events:
- all N share one
commit_position, - each gets an increasing
prepare_position, - the
WriteResult.log_positionreturns the position of the batch, which is the value you pass as the nextexpected_position.
This is why a single account, processed one command at a time, advances its commit_position by one per command while prepare_position tracks the global event sequence.
Positions and consistency
Command Context Consistency uses positions as the optimistic-lock token. You read a context, remember the position of its last event, and pass that as expected_position on the next write. If any newer event matched the context, the save is rejected with ALREADY_EXISTS.
Positions and paging
GetEvents reads a bounded page. To walk a boundary or a criteria set, page forward using the position of the last event you received:
- Call
GetEventswithfrom_position({-1, -1}for the first page) and acount. - Process the returned events.
- Use the
positionof the last event as thefrom_positionfor the next call. - Stop when a page returns fewer events than
count.
Reads return a stable committed prefix, so a page never contains events that a later page should have ordered before it. Because delivery and paging boundaries can overlap a position, keep consumers idempotent and deduplicate by event_id rather than assuming each event is seen exactly once.
Subscriptions
CatchUpSubscribeToEvents takes an after_position. It replays stored events ordered by position, then transitions to live delivery. A projector should persist the position of the last event it durably processed and resume from that position on restart. See Delivery Guarantees.