The timeout that charged twice
A checkout call times out. The client retries. Customers are charged twice, and your database shows one order.
A timeout is ambiguous: the charge may have completed and only the response was lost. The retry is correct behaviour — what's missing is something that lets the payment provider recognise the second attempt as the same attempt.
Boundaries, outermost first: One transaction: orders row (pending), an empty slot for the persist with the order Outside every boundary: Checkout, Payment provider (FAILED: charged twice), an empty slot for the on every attempt Connections: Checkout calls orders row (step 1) orders row calls persist with the order — same commit (step 2) persist with the order calls on every attempt (step 3) on every attempt calls Payment provider — retry-safe (step 4)