# External writes

Applies when: you call a system you do not control — a registry, a payment processor, a
control panel — and it can fail in the middle.

## The rule

**Never let local state be the answer to a question the authority can answer.**

Cache for display. Never cache for decisions.

If your table says the domain expires in March and the registry says January, the registry
is right and your customer's site goes dark in January. Your database does not get a vote.

This sounds obvious written down. It is not obvious at 2am when a page is slow and the
tempting fix is to trust the cached value one layer further up.

## The write that times out

When a payment times out you have a playbook: idempotency key, retry, reconcile.

When a **domain registration** times out, you do not know whether you just bought a domain.
The request may have landed. Retrying might register it twice, or fail because it is
already registered — to you, one second ago, by the request you thought failed.

The pattern that works:

1. Create an operation record **before** the call goes out.
2. Make the call.
3. On timeout, the record survives.
4. Reconcile by **reading back from the authority** and asking what actually happened.
5. The operation completes only when the authority agrees it did.

This feels like overkill right up until the first timeout, and then it is the only reason
you can answer the customer's question.

## Idempotency is not optional

A retry storm once double-charged three hundred real customers on a payment path that
looked fine in every test. Tests exercise the happy path. Production exercises the retry.

Every write to an external system needs to be safe to repeat. If the vendor gives you an
idempotency key, use it. If they do not, build the operation record above and reconcile.

## Failures that are business decisions, not error paths

The interesting failures are not exceptions. They are decisions with a deadline:

- Renewal fails because the card expired. Fail silently and the customer loses their
  domain. Retry forever and you hide a real problem. Alert immediately and at the wrong
  hour you have spammed them for nothing.
- A provisioning step fails halfway. Roll back and you may destroy something real. Continue
  and you have a half-configured tenant.

These need an escalation ladder designed with the business, not a `try/catch`. Get it right
and the category of problem disappears. Get it wrong and you have automated the failure.

## Build the exit

If you hold something on a customer's behalf — a domain, their data — make leaving easy.
Issue the transfer key on demand, from the panel, with no support ticket.

Plenty of platforms make this deliberately awkward. It is a mistake beyond the ethics of
it: a customer who cannot leave easily tells people you are hard to leave, and that costs
more than the churn ever would.

The engineering here is trivial. The decision is the thing, and it is worth making
deliberately rather than by neglect.

---
MIT licensed. Written by Smit Desai — <https://laravel.org.in>
