Locking Uncertain Outcomes Instead of Retrying Blindly
Most software failures are clear. The service said no, the card was declined, the file was too large. Clear failures are easy to handle: show a message, let the person try again.
A smaller group of failures is much harder. A request was sent to an outside service, and then the connection dropped, or the response timed out, or the reply was garbled. The other side may have done the work, or it may not. From where our system sits, the outcome is genuinely unknown.
For ordinary requests, a retry is fine. For requests that spend money or create something permanent, a blind retry can be expensive. Here is how we handle those cases.
Where uncertainty is costly
Some examples from our own platform show why this matters:
- Registering a domain. If the registration went through and we retry, we could pay for the same domain twice or end up with an error that hides the first success.
- Generating a paid AI image or document. If the provider completed the work and we retry, the customer could be charged for two generations.
- Issuing a refund. If the refund went through and we retry, the organization could refund more than it meant to.
- Charging a card. If the charge succeeded and we retry without protection, the customer pays twice.
In each case, doing the action twice is worse than waiting a little to learn what happened.
The lock
When one of these operations ends without a clear outcome, our system records it as uncertain and locks it against replay. The lock means no automatic retry, no second click and no background job can repeat the operation while its first attempt is unresolved.
The person who started the action sees an honest status, something like "we are confirming whether this completed," rather than a generic error that invites them to try again.
Finding out what actually happened
A locked operation is resolved by checking with the provider. Depending on the service, that might mean looking up the domain's registration status, checking the provider's record of the request or reviewing the payment in the processor's records. Once the real outcome is known, it is recorded: completed, with the right charges and records created, or failed, with any reserved amount returned.
For some services this check can be automated safely, using the provider's own records. For others, a person reviews it. Either way, the decision is based on what the provider says happened, not on a guess.
Idempotency helps, but is not enough
Where providers support idempotency keys, we use them, so a retried request returns the original result instead of repeating the work. You can read about that in idempotency: making sure a payment happens once. But not every provider or operation supports them, and even with keys, our own records must not claim success or failure until we know. The lock covers the gap.
Never fall back to a different provider
When a request is uncertain, it can be tempting to try a different provider instead, especially for AI features where several providers offer similar work. We do not. Switching providers in the middle of an uncertain request could produce two results and two bills. If our chosen route fails or is uncertain, we report it honestly, as described in failing closed.
What customers experience
From the customer's side, an uncertain outcome is rare and short-lived. They see a clear status, they are not charged twice and they are told when the outcome is settled. That is a much better experience than a duplicate charge they have to dispute, or a missing purchase they paid for.
A habit worth copying
If you build software that talks to payment, registration or AI services, it is worth asking for each call: what happens if this times out after the other side did the work? If the honest answer is "we would do it again," that call needs a lock.
Frequently asked questions
What should software do when a request times out?
For harmless requests, retrying is fine. For requests that spend money or create something permanent, the safest approach is to record the outcome as uncertain and confirm it with the provider before trying again.
Can a timeout charge me twice?
It can in poorly designed systems. Locking uncertain operations and using idempotency keys prevents duplicate charges from retries.
How are uncertain operations resolved?
By checking the provider's own records for what actually happened, then recording the operation as completed or failed accordingly.
Comments (0)
No comments yet. Be the first to share your thoughts!