Een time-out betekent niet dat een bewerking is mislukt: hij bevestigt alleen dat de client niet binnen de termijn een antwoord heeft ontvangen. De server kan de bestelling al hebben aangemaakt, de betalingsprovider kan de afschrijving hebben geaccepteerd of een asynchroon proces kan nog steeds worden uitgevoerd. Als de client ongecontroleerd opnieuw probeert, kan dezelfde bedrijfsintentie dubbele effecten veroorzaken.
Idempotentie in PHP maakt van een technische herhaling een opvraging of het teruggeven van het eerder verkregen resultaat. Het gaat niet om het negeren van alle duplicaten of uitsluitend vertrouwen op het feit dat de gebruiker niet tweemaal klikt. Het is een expliciet contract tussen client, API, persistentie en, waar van toepassing, externe systemen.
Het probleem: het antwoord gaat verloren, maar het effect blijft bestaan

Neem een endpoint dat een aankoop bevestigt. De applicatie valideert het verzoek, registreert de bestelling, vraagt de afschrijving aan en bereidt een antwoord voor. De verbinding wordt verbroken vlak voordat de client dat ontvangt. Bij het opnieuw versturen van hetzelfde formulier kan het endpoint niet uit de inhoud afleiden dat het om dezelfde aankoop gaat: twee bestellingen met dezelfde producten kunnen geldige en verschillende intenties zijn.
Het probleem doet zich ook voor bij het aanmaken van gebruikers, het toekennen van credits, het uitgeven van documenten, synchronisaties, webhooks en administratieve acties. Er zijn drie elementen die u het beste gescheiden houdt:
- Bedrijfsintentie: «ik wil deze specifieke aankoop bevestigen».
- Technisch verzoek: een HTTP-verzending met headers, body en authenticatiecontext.
- Uitvoeringspoging: elke interne verwerking, herhaalde wachtrijverwerking of aanroep naar een provider.
De idempotentiesleutel identificeert de intentie, niet een HTTP-verbinding of elke serverpoging. Daarom moet deze netwerkretries overleven en, wanneer de stroom dat vereist, procesherstarts.
Welke bewerkingen idempotentie nodig hebben en welke niet
Geef prioriteit aan bewerkingen die een resource aanmaken, bevestigen, innen, versturen, reserveren, melden of wijzigen met relevante gevolgen. Een POST /payments, de bevestiging van een bestelling of de ontvangst van een webhook zijn duidelijke kandidaten. Dat geldt ook voor een wachtrijtaak die meer dan één keer kan worden afgeleverd.
Een pure leesbewerking heeft normaal gesproken geen idempotentiesleutel nodig. Een update kan een andere semantiek hebben: het instellen van een gewenste toestand, zoals PUT /profiles/42, kan van nature idempotent zijn als dezelfde representatie de resource ongewijzigd laat. Een actie als «saldo verhogen» is dat daarentegen niet enkel door een bepaald werkwoord te gebruiken.
Een sleutel mag ook niet als vervanging voor andere regels worden gebruikt. Om twee conflicterende reserveringen in een beperkte voorraad te voorkomen, zijn domeininvarianten, gelijktijdigheidsbeheer en een reserveringsbeleid nodig. Om een taak in een gedistribueerde omgeving precies één keer uit te voeren, is de feitelijke aflevering doorgaans ten minste één keer; de verwerker moet duplicaten tolereren.
Ontwerp van de sleutel en het persistente record
De client moet een ondoorzichtige en voldoende onvoorspelbare sleutel genereren wanneer de bedrijfsintentie ontstaat, deze bewaren zolang opnieuw proberen mogelijk is en haar bijvoorbeeld in Idempotency-Key versturen. Als de server deze bij elke ontvangst genereert, kan hij een latere herhaling niet koppelen. In interne stromen kan de sleutel worden afgeleid van een stabiele identificatiecode van de bedrijfsgebeurtenis.
Het bereik moet de actor of tenant en de bewerking omvatten. Dezelfde tekenreeks mag niet botsen tussen twee accounts of tussen «bestelling aanmaken» en «terugbetaling uitvoeren». Definieer een bewaartermijn die aansluit op de werkelijke periode voor herhaalde pogingen en de risico's van het domein. Het record te vroeg verwijderen opent opnieuw de deur naar duplicaten; het onbeperkt bewaren verhoogt de kosten en vereist een privacy- en verwijderingsbeleid.
Een minimaal persistentiemodel omvat:
- beveiligingsbereik of tenant, bewerkingsnaam en idempotentiesleutel;
- cryptografische hash van een genormaliseerde payload;
- status:
processing,completed,failedofpendingwanneer externe bevestiging onzeker is; - antwoordcode en -body die herhaalbaar worden teruggegeven;
- identificatiecodes van de aangemaakte resource, interne correlatie en referentie van de externe provider;
- datums voor aanmaak, update en vervaldatum.
De hash voorkomt een belangrijke fout: dezelfde sleutel hergebruiken met andere gegevens. Reageer in die situatie met een conflict en verwerk de nieuwe payload niet. Om de vergelijking betrouwbaar te maken, normaliseert u velden waarvan de volgorde geen betekenis heeft en sluit u veranderlijke metadata uit die geen deel uitmaken van de intentie.
PHP-stroom: reserveer voordat u het effect veroorzaakt
De bescherming moet worden ondersteund door een unieke databasebeperking op het bereik, de bewerking en de sleutel. Eerst opvragen en daarna invoegen is niet voldoende: twee gelijktijdige verzoeken kunnen allebei vaststellen dat het record ontbreekt en tegelijk doorgaan.
De aanbevolen stroom is atomisch reserveren. Als de invoeging slaagt, is dat proces de initiële eigenaar van de uitvoering. Bij een uniekheidsconflict wordt het bestaande record gelezen, de hash geverifieerd en gehandeld volgens de status ervan. Een voltooid resultaat geeft exact het gepersisteerde antwoord terug; een lopende bewerking kan een status in afwachting teruggeven of slechts een begrensd interval wachten voordat het record opnieuw wordt opgevraagd.
begin transaction
insert idempotency_records(scope, operation, key, payload_hash, status)
values (?, 'create_order', ?, ?, 'processing')
-- de unieke beperking bepaalt de eigenaar
commit
if reservation_was_created:
result = execute_business_operation()
persist_completed_response(result)
else:
record = load_existing_record()
assert_same_payload_hash(record)
return replay_or_pending(record)Houd geen transactie of rijvergrendeling open tijdens een trage aanroep naar een provider. Dat verlaagt de capaciteit en kan langdurige blokkeringen veroorzaken. Reserveer en bevestig in plaats daarvan de lokale status in korte transacties. Als het externe effect en het lokale record moeten worden gecoördineerd, sla dan daarnaast een verzendopdracht op in een transactionele tabel en verwerk deze afzonderlijk. Dit patroon elimineert herhaalde pogingen niet, maar maakt het mogelijk om openstaand werk te herstellen zonder de geregistreerde intentie te verliezen.
Gelijktijdigheid, time-outs en onzekere statussen
Twee verzoeken met dezelfde sleutel kunnen met milliseconden verschil aankomen. De unieke beperking bepaalt welk verzoek de bewerking reserveert. Het tweede mag geen ander extern effect starten. Het kan 202 retourneren zolang de status processing of pending is, inclusief een identificatiecode om het resultaat op te vragen; als het contract een synchroon antwoord vereist, kan het beperkt wachten en het record opnieuw lezen.
Een fout vóór het starten van enig effect maakt het mogelijk om failed te markeren met een reproduceerbare fout. Een time-out bij een aanroep naar een extern systeem creëert echter onzekerheid: het is niet juist om automatisch als mislukt te markeren of zomaar een opdracht opnieuw te versturen. Bewaar de referentie van het verzonden verzoek, indien die bestaat, gebruik die referentie om de provider te raadplegen en stem het resultaat af. Zolang er geen bevestiging is, behoudt u pending en communiceert u dat het resultaat nog niet definitief is.
Ook de externe aanroep heeft een stabiele referentie nodig. Als de provider zijn eigen idempotentiesleutel ondersteunt, geef dan een sleutel door die aan dezelfde intentie is gekoppeld. Als deze dat niet ondersteunt, gebruik dan handelsidentificatiecodes, een latere raadpleging, periodieke afstemming en operationele procedures voor de dubbelzinnige gevallen. Geen enkele lokale transactie kan een schrijfbewerking in de database en een onafhankelijke externe API atomisch maken.
Wat een idempotentiesleutel niet oplost
Idempotentie voorkomt het herhalen van een herkende intentie; het bepaalt niet hoe een onomkeerbaar effect moet worden teruggedraaid. Een fysieke verzending, een reeds afgewikkelde overboeking of een melding die een gebruiker heeft gezien, kan compensatie, annulering of handmatige afhandeling vereisen. Ontwerp deze acties als expliciete bedrijfsprocessen, met machtigingen, statussen en controleerbaarheid.
Verwar een correctie ook niet met een herhaalde poging. Als de gebruiker na een fout het adres, bedrag of de producten wijzigt, is er sprake van een nieuwe intentie en moet een nieuwe sleutel worden gebruikt. Het hergebruiken van de vorige met een andere payload moet een conflict opleveren, niet de oorspronkelijke bewerking stilzwijgend bijwerken.
Tests, waarneembaarheid en controlelijst

Test meer dan alleen het ideale pad. Onderbreek het antwoord nadat het resultaat is gepersisteerd, herhaal dezelfde sleutel parallel, herstart een worker na het reserveren van het record en simuleer een time-out nadat een extern verzoek is verzonden. Controleer dat er slechts één bedrijfsresource bestaat, dat het herhaalde antwoord hetzelfde resultaat behoudt en dat een andere payload met dezelfde sleutel niet wordt geaccepteerd.
Leg, zonder gevoelige gegevens bloot te leggen, de sleutel of een veilige afgeleide identificatiecode, het bereik, de status, de correlatie en de externe referentie vast. Metrieken voor sleutelconflicten, bewerkingen die te lang in afwachting zijn en onopgeloste afstemmingen helpen ondersteuning en beheer om een normale herhaalde poging van een incident te onderscheiden.
- Vertegenwoordigt de sleutel een bedrijfsintentie en heeft deze een gedefinieerd bereik?
- Bestaat er een unieke beperking die twee gelijktijdige reserveringen voorkomt?
- Wordt een hash van de payload vergeleken en worden wijzigingen in intentie afgewezen?
- Wordt een antwoord of resultaat gepersisteerd dat consistent kan worden herhaald?
- Maken onzekere statussen raadpleging en afstemming mogelijk vóór opnieuw proberen?
- Beschikt elk extern effect over een referentie, herstel en operationeel alternatief?
- Zijn duplicaten, uitval, herhaalde wachtrijverwerking en werkelijke gelijktijdigheid getest?
Zo toegepast belooft idempotentie niet dat een netwerk betrouwbaar is. Het zorgt ervoor dat onvermijdelijke fouten een beheersbaar, traceerbaar en consistent resultaat voor het bedrijf krijgen.



