Part 10 of 16 · Day 2 · idempotence

Unknown outcome: did it go through or not?

Problem and experience

The payout timed out. Did it go through or not?

The call to the payment system ends in a timeout. The money may or may not have gone out. Sending the payout again is a risk.

  1. Disbursement
  2. Payment system
  3. Timeoutno response
  4. Sent?yes / no / unknown

Blind retry

  1. Second payout
  2. The client received the money twice

From practiceWhen did you have to decide whether to retry an operation without knowing the result?

TakeawayAn unknown outcome is neither failure nor success. It is a third state.

More on this topic

What it means

An unknown outcome arises when the confirmation does not arrive, but the operation may have gone through. A lost ack is a typical example.

Why we use it

A blind retry creates a duplicate; not retrying creates a loss.

When it makes sense

For all operations with a side effect in an external system: payments, payouts, e-mails.

Where it breaks

  • Treating a timeout as a failure.
  • Retrying without an operation key.
  • Not deciding who finds out the actual state.

Imagine

Disbursement sends the payout and the response is lost. The system tries again. The client receives the money twice.

The worst thing about an unknown outcome is not failure, but not knowing what happened.

Principle, application and exercise

Business idempotency and status checks

Every disbursement has a business key. A retry returns the original result, and an unclear state is verified by a query.

Disbursement key

  1. Requestkey = applicationId
  2. Recipienthave this key already?
  3. yes: original result
  4. no: execute

Unknown outcome

  1. Timeout
  2. Status queryGET /disbursements/{key}
  3. Decisionretry / close

Trade-offThe key must have business meaning and the retention period must cover the longest retry. Status checking is another process that has to be monitored.

TakeawayIdempotency is a property of the receiver, not the sender.

More on this topic

What it means

Business idempotency uses a key from the business domain (application number, disbursement number). Technical deduplication by eventId alone is not enough when the retry originates elsewhere.

Why we use it

The receiver is the only place where a duplicate can be reliably stopped.

When it makes sense

For every receiver with a side effect.

Where it breaks

  • Duplicate check outside the transaction with the effect.
  • Deduplication by eventId only.
  • Unbounded growth of records.

Imagine

The account-opened event arrives twice. With a key, we get one account and the original account number.

It is not about forbidding duplicates, but making them harmless.

Training for your team

Would you like this training for your team?

We run the training on your code and your domain problem. We agree the scope, dates and format with you.

Discuss the training