AlgoMaster Logo
AlgoMasterConsume Outbox Events Idempotently and in Orderhard

Consume Outbox Events Idempotently and in Order

hard

Transactional outbox relays normally provide at-least-once delivery. Consumers must therefore reject duplicates, and per-aggregate sequence numbers can prevent later events from being applied before missing predecessors.

Design an OrderedEventConsumer class:

  • OrderedEventConsumer() creates an empty consumer.
  • String apply(String aggregateId, int sequence, int delta) processes one event.
  • int balance(String aggregateId) returns that aggregate's accumulated balance.
  • int lastSequence(String aggregateId) returns its last applied sequence.

Every unseen aggregate starts with balance 0 and last sequence 0. For an incoming event:

  • If sequence <= lastSequence, return "DUPLICATE" and change nothing.
  • If sequence > lastSequence + 1, return "GAP" and change nothing. Gapped events are not buffered.
  • Otherwise, add delta to the balance, set the last sequence to sequence, and return "APPLIED".

State is independent for each aggregate. A gapped event can be delivered again after its missing predecessors have been applied.

Example 1:

Input:

Output:

Explanation: Sequence 1 changes the balance once. The repeated delivery is recognized from the stored sequence and has no effect.

Example 2:

Input:

Output:

Explanation: Sequence 2 cannot cross the gap. Once sequence 1 is applied, redelivered sequence 2 is accepted.

Constraints

  • 1 <= aggregateId.length <= 40
  • 1 <= sequence <= 10^9
  • -10^6 <= delta <= 10^6
  • Balances remain within the signed 32-bit integer range.
  • At most 1000 method calls are made per object.
Hints

Loading...
CallReturns
new OrderedEventConsumer()null
apply("acct-1", 1, 100)"APPLIED"
apply("acct-1", 1, 100)"DUPLICATE"
balance("acct-1")100
lastSequence("acct-1")1

The first delivery advances acct-1. Redelivering the same sequence has no second balance effect.

Run checks these cases. Submit also runs a larger hidden set.