Public repository, MIT, synthetic data
The operation succeeded.
The answer never came back.
A booking-to-billing sample where the timeout lands after the external effect, not instead of it. The worker restarts knowing nothing. What the resume does, and what it refuses to do, is the whole repository.
The simulated provider keeps its effects in PostgreSQL, on its own connection, and commits them before the caller is told anything, so they survive the restart. The intent is committed before the call, with a key derived from the line and the parameters frozen. Inside the provider retention window the resume presents that same key and the stored result is replayed. Outside it nothing is sent at all, because a forgotten key creates a new request rather than replaying the old one: the line is marked unresolved and the outcome is looked up instead. That last branch is the one that usually does not exist.
Python 3.12, FastAPI, SQLAlchemy 2, Alembic, PostgreSQL. 60 tests on a real database, the nominal path among them, because otherwise no duplicate operations is a result you also get from nothing ever working. Every protection has a switch, and a test turns each one off to show the dangerous outcome then happens. The run that matches this report is in continuous integration.
Failure cases to check against your design
Two more, and both end in the same place: a record that is fine, code that is fine, and nobody able to say what is true. The interesting question is not how they are detected but what the next billing run does when it meets one.
Same identity, same version, different content.
Two payloads carry the same booking reference and the same updatedAt, and disagree. Last write wins looks like a tie break and is a coin toss; the loser is invisible, because nothing in the data afterwards says an update was dropped. Neither is applied, both are kept, the booking goes on hold, and the sentence to send is generated rather than written by hand: “These two records have the same booking ID and updatedAt but different statuses. Can updatedAt identify a revision, or is there a separate sequence?”
tests/test_conflict_and_quarantine.pyA value nobody declared, about a booking that is live.
Mapping an unknown status onto the nearest known one is how an obligation gets billed for a booking that was put on hold. The message is held with the question attached, the billing preparation for that booking is suspended, and one replay releases it. That the hold is conservative is a demonstration choice, listed as one.
tests/test_conflict_and_quarantine.pyConcurrency on two real connections, a cancellation in the three places it can land, and two sources that diverge in meaning rather than only in shape, are in the repository.
What needs confirmation
The sample reproduces a few publicly described failure paths. It is not a review of your architecture, which I have not seen.
- The data
- Everything is synthetic. Both partners are fictional, and the payment provider is a stand-in that reproduces three behaviours Stripe documents for idempotent creates: the same key with the same parameters replays, the same key with different parameters is an error, and a key is only retained for 24 hours. No network call is made, and nothing in the repository has ever held a payment key.
- What it establishes
- Within this model, a lost answer does not become a second operation. It does not validate an integration with a real provider, which the sample does not exercise. Reception, preparation, submission and settlement are four steps, and this one stops at the third.
- Demonstration decisions
- An undecidable booking is not prepared; a collision keeps the version already held; a cancellation after an established operation is left for a person. Each is defensible and so is its opposite, which is why they are written down rather than assumed.
- Open questions
- Whether the partner reference names one booking for life, whether the event id is stable across retries, and whether the money field is per unit or per booking. Nothing on this side turns those into guarantees.
- Where I work
- I work from Paraguay, not from the EU. This sample uses synthetic data only.
The full list, including what only a partner could ever confirm, is in docs/what-needs-confirmation.md.