Tapahtumapohjainen jo suunnittelusta: näin yhdestä maksusta tulee kanta-asiakaspisteitä, pysyvyyttä ja kuitti
Varausalusta elää tai kuolee johdonmukaisuudesta. Näin yksi Stripe-maksu leviää kanta-asiakaspisteiksi, pysyvyystiedoksi, kuitiksi ja kirjanpitoriviksi, miksi jokainen vaikutus on kytketty todelliseen tilanmuutokseen ja minne viemme arkkitehtuuria seuraavaksi.
Kun asiakas maksaa varauksen, ennakkomaksun, paketin tai jäsenyyden, tuon yhden tapahtuman pitäisi liikuttaa koko järjestelmää. Hänen kanta-asiakassaldonsa pitäisi kasvaa. Hänen pitäisi laskea taas aktiiviseksi eikä nukkuvaksi. Hänen pitäisi saada kuitti. Ja rahan pitäisi päätyä kirjanpitoon täsmäytystä varten. Jos yksi noista menee pieleen, tuote menettää hiljaa luottamusta: jäseneltä veloitetaan mutta hänen krediittinsä eivät koskaan ilmesty, tai Stripen uudelleenyritys laskee myynnin kahteen kertaan.
Jonkin aikaa jokainen noista oli oma saarekkeensa. Webhook merkitsi asiat maksetuiksi ja pysähtyi siihen. Siksi teimme maksusta tapahtuman ja annoimme muun järjestelmän reagoida siihen.
Malli: haarauta, mutta vain aidon tilanmuutoksen kohdalla

Stripe lähettää checkout.session.completed-tapahtuman yhteen webhookiin. Käsittelijä tekee ensin rahan kannalta kriittisen kirjoituksen (merkitse ennakkomaksu maksetuksi, käännä lasku maksetuksi, myönnä pakettikrediitti) ja kutsuu sitten yhtä jaettua funktiota, applyPaidRipplea, sitouttamisen puolta varten. Aaltoilu on parhaan yrityksen varassa: jokainen askel on käärittynä niin että virhe kirjautuu lokiin ja niellään, koska oikuttelevan sähköpostipalvelun ei saa koskaan estää meitä kirjaamasta oikeaa maksua.
// In the webhook, after the money-critical write succeeds:if (fresh) { await applyPaidRipple({ orgId, customerId, amountCents, loyaltyReason: "Package purchase", receiptTo: email, receiptDedupeKey: `payment_receipt:package:${session.id}`, });}// applyPaidRipple: loyalty -> lastVisitAt bump -> transactional receipt,// each in its own try/catch. The ledger write runs unconditionally below.Idempotenssi on koko peli
Stripe toimittaa saman tapahtuman useammin kuin kerran. Se on ominaisuus eikä bugi, ja se tarkoittaa että jokaisen käsittelijän on oltava turvallinen ajaa kahdesti. Meitä suojaa kaksi kerrosta. Ensin tapahtuman id kirjataan käsiteltyjen tapahtumien tauluun uniikkirajoitteen kanssa, joten täsmälleen saman tapahtuman uusi toimitus oikosulkeutuu. Toiseksi, ja tärkeämpänä, jokainen polku kytkee oman aaltoilunsa omaan aitoon tilanmuutokseensa: totuusarvoon joka on tosi vain sillä kerralla kun rivi oikeasti kääntyy.
// markInvoicePaid flips 'open' -> 'paid' and returns true ONLY on that// real transition. A redelivery sees 'paid' already and returns false.const flipped = await markInvoicePaid(invoiceId, paymentIntentId, amountTotal);if (flipped) { await applyPaidRipple({ /* ...loyalty, retention, receipt */ });}// So even if the event-id dedupe is bypassed, the ripple still fires once.Kaksoiskappaleiden tunnistusavain ei ole mukava lisä. Se on ero sen välillä että jäsentä kiitetään kerran ja että häneltä veloitetaan kahdesti.
Minne tämä on menossa
Tänään aaltoilu on prosessin sisäinen haarautuminen, mikä on oikea määrä koneistoa siihen missä olemme: se on yksinkertainen, transaktionaalinen ja helppo ymmärtää. Mutta webhook on tarkoituksella sauma, ja tiekartta muuttaa sen sauman kestäväksi tapahtumaväyläksi. Muoto pysyy samana; toimitus vahvistuu.
- Jono jokaisen vaikutuksen eteen (kanta-asiakkuus, pysyvyys, viestintä), jotta hidas kuluttaja ei koskaan pidättele webhookia ja uudelleenyritykset tapahtuvat automaattisesti kasvavalla viiveellä.
- Outbox-taulu joka kirjoitetaan samassa transaktiossa rahan kanssa ja välitetään sitten väylälle, jottei vaikutus koskaan katoa maksetun ja julkaistun väliin.
- Raskaimpien kuluttajien (ilmoitukset, pysyvyyspisteytys) eriyttäminen omiin julkaistaviin palveluihinsa kuorman kasvaessa, samalla kun ydinvarauksen kirjoitus pysyy yhtenä vahvasti johdonmukaisena yksikkönä.
- Hallinnoitu tapahtuma- ja jonokerros pilvessämme, jotta skaalaus on konfiguraatiomuutos eikä migraatio.
Opetus joka pätee kaikkeen tähän: pidä rahapolku vahvasti johdonmukaisena ja synkronisena, ja tee kaikesta siitä riippuvasta tapahtumapohjaista, idempotenttia ja parhaan yrityksen varassa toimivaa. Maksu on tosiasia. Kaikki hyvä joka siitä seuraa on reaktio, ja reaktioiden pitää olla turvallisia toistaa.