Keperluan dan Konteks Berkenaan
Reka bentuk sebuah sistem pemprosesan pembayaran e-dagang. Selepas pembeli menyerahkan pesanan, sistem menggunakan penyedia perkhidmatan pembayaran (PSP) luaran untuk memproses pembayaran kad sekali guna. Ia mengesahkan (authorize) semasa pembayaran, menangkap (capture) selepas inventori ditempah, dan melepaskan pengesahan jika pesanan dibatalkan. Selepas penangkapan, ia menyokong beberapa bayaran balik sebahagian, tetapi jumlah kumulatifnya tidak boleh melebihi jumlah yang ditangkap. Kaedah pembayaran mungkin memerlukan pengesahan tambahan seperti 3DS, dan hasil akhir mungkin tiba selepas pelayar kembali.
Andaikan lima juta percubaan pembayaran setiap hari, kira-kira 58 TPS secara purata dan 500 TPS pada waktu puncak. API cipta-pembayaran mempunyai p99 di bawah 300 milisaat, bacaan status mempunyai p99 di bawah 200 milisaat, dan API tempatan mempunyai sasaran ketersediaan bulanan 99.99%. Ketersediaan tersebut tidak menjanjikan penyelesaian oleh penyedia. Wang adalah integer dalam unit terkecil (minor unit) mata wang tersebut, dan satu pembayaran mempunyai tepat satu mata wang. Penyedia, rangkaian, dan proses tempatan semuanya boleh gagal. Angka dan garis masa ini hanyalah andaian temu bual, bukan janji yang dibuat oleh produk pembayaran sebenar.
Skop merangkumi penciptaan pembayaran, pengesahan tambahan, pengesahan (authorization), penangkapan (capture), pembatalan pengesahan, bayaran balik sebahagian dan penuh, lejar wang, webhook penyedia, serta penyelarasan. Caj balik (chargebacks), model penipuan, pertukaran mata wang asing, pembayaran keluar pedagang (merchant payouts), cukai, dan program pematuhan PCI yang lengkap adalah di luar skop, tetapi jawapan hendaklah mengenal pasti sempadan tersebut. Halaman yang dihoskan atau komponen penokenan (tokenization) penyedia mengumpul butiran kad. Sistem ini menyimpan token kaedah pembayaran dan tidak boleh menerima atau merekodkan nombor kad mentah atau kod keselamatan.
Perkara yang Dinilai oleh Penemu Bual
Isyarat pertama adalah sama ada calon memisahkan niat perniagaan, percubaan penyedia, dan fakta wang. Satu troli dipetakan kepada satu payment_id dalaman, tetapi ia boleh mempunyai beberapa percubaan pengesahan atau penyedia. Permintaan yang tamat masa juga tidak membayangkan pembayaran gagal. Jawapan yang kukuh tidak memampatkan keseluruhan kitaran hayat ke dalam paid=true. Ia menyimpan agregat pembayaran, setiap operasi dan hasil yang tidak diketahui, rujukan penyedia, serta entri lejar secara berasingan.
Isyarat kedua ialah penaakulan yang tepat merentasi sempadan teragih. Transaksi pangkalan data tidak boleh memasukkan penyedia pembayaran luaran secara atomik. Penyedia mungkin melakukan penangkapan sedangkan responsnya hilang, webhook mungkin tiba sebelum respons segerak, atau sesuatu proses mungkin ranap selepas komit tempatan. Kunci keidempotenan pemanggil, ID operasi dalaman, kunci keidempotenan penyedia, outbox transaksi, penyahduplikasian webhook, dan carian status menjadikan pelaksanaan berulang menumpu (converge). Semua ini tidak mewujudkan transaksi tepat-sekali-sahaja (exactly-once) hujung-ke-hujung.
Isyarat ketiga ialah mesin keadaan yang monotonik dan boleh diaudit. Pengesahan dan penangkapan adalah peringkat wang yang berbeza. REQUIRES_ACTION bukanlah satu kegagalan, dan tamat masa penyedia yang menghasilkan operasi UNKNOWN tidak boleh menggagalkan pembayaran serta-merta. Bayaran balik mesti merujuk kepada pembayaran yang telah ditangkap, menggunakan wang yang tepat, dan mengekalkan batas tak varian bahawa bayaran balik yang disahkan ditambah bayaran balik yang sedang berjalan (in-flight) tidak melebihi jumlah yang ditangkap di bawah konkurensi.
Isyarat keempat ialah pembahagian antara keadaan aliran kerja dan perakaunan. Jadual pembayaran menjawab perkara yang boleh dilakukan pengguna seterusnya. Lejar tambah-sahaja (append-only) menjawab sebab baki mempunyai nilai semasanya. Fakta yang telah dicatatkan tidak pernah disunting di tempat asalnya; bayaran balik dan pembetulan menambah entri pembalik atau pampasan. Debit, kredit, mata wang, dan rujukan perniagaan bagi setiap jurnal disahkan secara transaksi dan kemudian diselaraskan dengan laporan penyedia serta deposit bank.
Isyarat terakhir ialah keselamatan dan kebolehfalsafahan (falsifiability). Jawapan harus mengurangkan pendedahan data kad, mengesahkan tandatangan webhook, melindungi rahsia penyedia, mengehadkan kebenaran dan log, serta menyuntik respons yang hilang, webhook pendua atau tidak mengikut urutan, penangkapan dan bayaran balik serentak, jurnal tidak seimbang, dan percanggahan penyelarasan. Rajah perkhidmatan tanpa batas tak varian, laluan pemulihan, dan pengesahan tidak membuktikan ketepatan sistem.
Soalan untuk Dijelaskan Sebelum Menjawab
- Siapakah yang mengumpul data kad? Keperluan ini menggunakan halaman yang dihoskan atau komponen penokenan penyedia. Bahagian belakang (backend) perniagaan hanya menerima token kaedah pembayaran dan tidak menyimpan nombor kad mentah, data trek, PIN, atau kod keselamatan. Pasukan pematuhan masih perlu mengesahkan skop PCI yang sebenar.
- Bilakah pengesahan dan penangkapan berlaku? Lakukan pengesahan semasa penyerahan pesanan dan tangkap selepas tempahan inventori. Batalkan sebelum tamat tempoh jika inventori gagal. Jadual keupayaan menentukan sama ada kaedah pembayaran menyokong penangkapan tertangguh; reka bentuk tidak boleh menganggap bahawa semua kaedah menyokongnya.
- Apakah yang menetapkan kejayaan? Pengalihan pelayar hanyalah isyarat pengalaman pengguna dan tidak boleh membenarkan pemenuhan pesanan (fulfillment). Respons penyedia yang disahkan, webhook, atau pertanyaan aktif membekalkan bukti berwibawa, yang mesti diterima oleh mesin keadaan tempatan sebelum tindakan perniagaan berlaku.
- Apakah kontrak bayaran balik? Sokong beberapa bayaran balik sebahagian dan bayaran balik penuh, tidak pernah melebihi penangkapan. Tiada bayaran balik mandiri tanpa pembayaran asal. Bayaran balik boleh diselesaikan secara tak segerak atau ditolak oleh penyedia.
- Adakah kita memerlukan berbilang penyedia? Versi satu mempunyai satu penyedia, tetapi antara muka menyimpan ID operasi dalaman dan rujukan penyedia. Jangan sekali-kali melakukan failover secara automatik semasa hasil tidak diketahui, kerana kedua-dua penyedia boleh mengenakan caj.
- Apakah yang diliputi oleh lejar? Keperluan ini merekodkan akaun belum terima pemproses (processor receivable) dan akaun belum bayar pedagang (merchant payable). Yuran penyedia, pembayaran keluar pedagang, dan cukai adalah di luar skop. Setiap mata wang diimbangi secara bebas; tiada wang titik terapung (floating-point) atau kadar pertukaran tersirat dibenarkan dalam lejar.
- Apakah keperluan pengekalan dan audit? Kekalkan pembayaran, operasi, resit webhook, dan rujukan lejar mengikut dasar peraturan dan syarikat, di samping meminimumkan, menyulitkan, dan mengaudit akses kepada muatan sensitif. PCI SSC melarang penyimpanan data pengesahan sensitif selepas pengesahan, walaupun disulitkan.
- Bagaimanakah pertukaran (trade-off) antara ketersediaan dan ketekalan diuruskan? Jika penyedia tidak tersedia, sistem boleh menerima tugas dan menunjukkan "memproses", tetapi ia tidak boleh menunjukkan kejayaan palsu. Ketepatan dan kebolehkesanan wang diberi keutamaan berbanding respons terminal serta-merta.
Rangka Kerja Jawapan 30 Saat
"Saya akan menggunakan payment_id yang stabil untuk satu niat pembayaran dan memisahkan keadaan pembayaran daripada operasi pengesahan, penangkapan, dan bayaran balik. Kunci keidempotenan pemanggil secara atomik menyimpan ringkasan (digest) permintaan, operasi, dan outbox; pekerja (worker) menggunakan semula ID operasi pada penyedia. Tamat masa menjadi UNKNOWN dan menumpu melalui webhook yang disahkan, carian, dan penyelarasan dan bukannya caj baharu. Hasil yang berwibawa memajukan mesin keadaan monotonik dan secara atomik menambahkan jurnal yang seimbang serta peristiwa perniagaan. Penciptaan bayaran balik secara bersyarat menempah nilai boleh dibayar balik yang tinggal. Laporan penyedia dan deposit bank kemudiannya menyelaraskan lejar dalaman. Penokenan penyedia memastikan data kad berada di luar backend, dan halaman kejayaan pelayar tidak boleh mencetuskan pemenuhan pesanan."
Perbincangan Mendalam Langkah demi Langkah
Langkah 1: Mulakan dengan kapasiti, batas tak varian, dan pemilikan
Lima juta dibahagikan dengan 86,400 saat adalah kira-kira 58 TPS. Kemuncak 500 TPS tidak memerlukan setiap jadual di-shard pada hari pertama. Ketepatan, kebolehauditan, dan pemulihan merentasi sempadan luaran menguasai reka bentuk ini. API pembayaran diskalakan secara mendatar, pangkalan data hubungan memegang keadaan yang berwibawa, dan giliran tahan lasak (durable queue) yang dihalakan oleh payment_id menyerap lonjakan dan mengasingkan kependaman penyedia. Nyatakan batas tak varian terlebih dahulu:
amount > 0
currency is immutable after the first provider attempt
captured_amount <= authorized_amount
refunded_amount + pending_refund_amount <= captured_amount
for every journal: sum(debits) == sum(credits), per currency
one merchant + one idempotency_key describes one immutable request intent
one successful business operation produces at most one journal referencePada skala ini, pangkalan data hubungan dengan satu rantau tulis dan failover menjadikan kunci keidempotenan, versi keadaan, dan susunan lejar lebih mudah dipelihara berbanding penulisan berbilang rantau aktif-aktif. Aktif-aktif boleh mengurangkan masa failover serantau, tetapi ia mesti menyelesaikan penggunaan serentak bagi kunci yang sama dan operasi wang yang bercanggah; ia hanya wajar jika terdapat keperluan ketersediaan serantau yang eksplisit. Event sourcing penuh juga mengekalkan sejarah tetapi menyebarkan kerumitan main semula (replay), migrasi skema, dan pertanyaan ke seluruh aliran kerja pembayaran. Reka bentuk ini hanya mengekalkan jurnal wang sebagai tambah-sahaja dan menggunakan agregat semasa berversi untuk keadaan aliran kerja, memadankan faedah audit dengan kos operasi.
Perkhidmatan pesanan memiliki inventori dan pemenuhan pesanan. Perkhidmatan pembayaran memiliki keadaan pembayaran, operasi, dan rujukan kepada fakta wang. Penyedia memiliki keadaan rangkaian kad. Lejar memiliki fakta wang dalaman. Perkhidmatan pesanan tidak boleh menulis baris pembayaran secara langsung, dan webhook pembayaran tidak boleh terus menandakan pesanan telah dihantar. Perkhidmatan pembayaran menerbitkan peristiwa perniagaan yang stabil yang digunakan oleh perkhidmatan pesanan secara idempoten mengikut payment_id.
Langkah 2: Tentukan API, sesi keidempotenan, dan model data
Antara muka teras boleh menjadi:
POST /payments create one payment for an order
POST /payments/{id}/capture capture an authorized amount
POST /payments/{id}/cancel cancel an uncaptured authorization
POST /payments/{id}/refunds request a partial or full refund
GET /payments/{id} return current status and allowed next actions
POST /provider/webhooks persist a verified provider eventSetiap panggilan yang mengubah wang memerlukan kunci keidempotenan yang disediakan oleh pemanggil. Kekangan unik pada (merchant_id, operation_type, idempotency_key) melindungi ringkasan permintaan ternormal, keadaan dalam proses, dan respons yang boleh dimainkan semula. Permintaan pertama mencipta payments, payment_operations, dan rekod outbox dalam satu transaksi pangkalan data. Kunci dan ringkasan yang sama memainkan semula respons yang diketahui. Kunci yang sama dengan jumlah, mata wang, pembayaran, atau jenis operasi yang berbeza mengembalikan konflik. Panduan kejuruteraan pihak pertama Amazon turut mengesyorkan ID permintaan yang disediakan oleh pemanggil dan sempadan ACID yang merangkumi kedua-dua ID dan mutasi tersebut; ID yang digunakan semula dengan niat berbeza akan ditolak.
Simpan tanggungjawab secara berasingan:
payments: rujukan pesanan, jumlah, mata wang, keadaan agregat, jumlah disahkan/ditangkap/dibayar balik, dan versi;payment_operations: jenis, ID operasi, jumlah yang diminta, keadaan, penyedia, rujukan penyedia, percubaan, dan sebab tidak diketahui;provider_events: ID peristiwa penyedia, hasil tandatangan, masa diterima, rujukan muatan disulitkan, dan keadaan pemprosesan;journal_entries: ID jurnal, akaun, debit atau kredit, jumlah, mata wang, dan rujukan operasi;outbox_events: peristiwa perniagaan yang dikomit secara tempatan dan menunggu penerbitan.
ID operasi dalaman boleh menjadi kunci keidempotenan penyedia. Adyen mendokumentasikan percubaan semula yang selamat dengan kunci yang sama selepas tamat masa pembayaran, bersama-sama dengan skop kunci, pengekalan, dan had rentas rantau. Oleh itu, sistem ini memodelkan kontrak penyedia sebenar dan bukannya menganggap UUID sebagai jaminan global yang kekal.
Langkah 3: Modelkan pembayaran dan operasi sebagai dua mesin keadaan
Agregat pembayaran ialah kitaran hayat yang menghadap pesanan dan pengguna:
CREATED -> REQUIRES_ACTION -> AUTHORIZED -> CAPTURED
\-> FAILED \-> CANCELED
CAPTURED -> PARTIALLY_REFUNDED -> REFUNDEDSetiap pengesahan, penangkapan, pembatalan, atau bayaran balik mempunyai kitaran hayat operasi yang bebas:
PENDING -> SUCCEEDED | FAILED | UNKNOWN
UNKNOWN -> SUCCEEDED | FAILED (after query, webhook, or reconciliation)FAILED bermaksud bukti berwibawa menyatakan operasi ini tidak akan berjaya kemudian. Tamat masa rangkaian, 5xx, atau respons yang hilang adalah UNKNOWN. Agregat hanya menerima peralihan monotonik yang sah. Webhook yang melaporkan keadaan lama dikekalkan untuk audit tetapi tidak boleh menggerakkan agregat ke belakang. Apabila webhook dan pertanyaan aktif berlumba (race), versi baris atau kemas kini bersyarat mengkomit peralihan sekali sahaja. Stripe mendokumentasikan niat pembayaran sebagai sumber yang merangkumi penciptaan melalui pembayaran, termasuk pengesahan tambahan, dan pembayaran tangkapan manual sebagai boleh ditangkap sebelum penangkapan dilakukan. Ini menyokong sumber pembayaran yang tahan lama dan bukannya menyamakan pembayaran dengan satu respons HTTP.
Pengesahan pesanan dipisahkan daripada pengesahan inventori. Kejayaan inventori mencetuskan penangkapan, manakala kegagalan mencetuskan pembatalan. Operasi tersebut boleh berlumba, jadi kemas kini pangkalan data bersyarat membenarkan hanya satu operasi menuntut versi AUTHORIZED semasa. Webhook mungkin tiba sebelum panggilan penyedia kembali. Kedua-dua respons segerak dan webhook mesti memasuki fungsi aplikasi keadaan yang sama dan bukannya melaksanakan dua laluan peralihan.
Langkah 4: Terima ketidakatomikan luaran dan jadikan aliran kerja menumpu
Transaksi tempatan mengkomit keadaan operasi bersama-sama outbox. Relay menerbitkan sekurang-kurangnya sekali, dan pekerja menuntut mengikut ID operasi. Pekerja menggunakan semula ID tersebut sebagai kunci keidempotenan penyedia dan menggunakan had masa sambungan, permintaan, dan jumlah masa yang terikat. Hasil yang pasti menyimpan rujukan penyedia dan ringkasan respons. Respons yang hilang menandakan UNKNOWN dan menjadualkan carian status. Ia tidak pernah mencipta operasi baharu atau menukar penyedia secara membuta tuli.
Terdapat tiga tetingkap keranapan penting:
- Keranapan sebelum transaksi tempatan dikomit tidak meninggalkan operasi yang kelihatan, jadi pemanggil mencuba semula dengan kunci yang sama.
- Pengakuan penerbitan yang hilang selepas komit outbox menyebabkan relay menerbitkan semula; pekerja menuntut operasi yang sama.
- Kejayaan penyedia dengan respons yang hilang menggunakan kunci penyedia yang sama, carian rujukan penyedia, atau webhook untuk menumpu.
Ini membekalkan ungkapan yang boleh dicuba semula dan boleh diaudit bagi satu niat, bukannya transaksi merentasi syarikat. Jika hasil masih tidak diketahui selepas tetingkap pengekalan keidempotenan penyedia, percubaan semula automatik akan dihentikan. Laporan penyedia dan pengendali mesti menentukan hasilnya; masa yang berlalu sahaja tidak membuktikan kegagalan.
Langkah 5: Terima webhook tak segerak dengan selamat dan toleransi susunan semula
Titik akhir (endpoint) mengekalkan badan permintaan mentah dan mengesahkan tandatangan serta tetingkap cap masanya dengan rahsia semasa dan rahsia lama dalam tempoh penggiliran (rotation period). Ia menolak tandatangan yang tidak sah. Resit (provider, provider_event_id) yang unik dikekalkan, selepas itu titik akhir mengembalikan 2xx dengan cepat dan memasukkan pemprosesan tak segerak ke dalam giliran. Log mengandungi ID peristiwa, rujukan penyedia, dan kod sebab, bukannya muatan sensitif atau rahsia yang lengkap.
Webhook boleh diduplikasi, ditangguhkan, dan disusun semula. Stripe secara eksplisit mendokumentasikan percubaan semula mod langsung automatik dan tiada jaminan susunan peristiwa. Pengendali tidak boleh menganggap pengesahan sentiasa tiba sebelum penangkapan. Ia boleh mengambil sumber semasa penyedia melalui rujukan objek peristiwa, atau memetakan fakta luaran kepada peralihan tempatan yang dibenarkan. Setiap peristiwa dinyahduplikasi melalui ID operasi atau rujukan penyedia yang sama. Penangkapan yang telah dicatatkan tidak boleh dicatatkan dua kali, dan pengesahan lama tidak boleh menurunkan CAPTURED kepada AUTHORIZED.
Pelayar hanya meninjau (poll) atau melanggan keadaan pembayaran tempatan. Parameter "kejayaan" pada URL pulangan tidak boleh memenuhi pesanan, dan klien tidak boleh menyerahkan CAPTURED. Selepas kejayaan penangkapan yang berwibawa dan komit lejar, perkhidmatan pembayaran menerbitkan PaymentCaptured melalui outbox. Perkhidmatan pesanan memenuhi pesanan secara idempoten mengikut ID peristiwa.
Langkah 6: Nyatakan fakta wang dengan lejar tambah-sahaja
Keadaan pembayaran ialah paparan operasi; lejar ialah rekod audit wang. Keperluan ini memudahkan perakaunan kepada dua akaun: belum terima pemproses ialah aset dan belum bayar pedagang ialah liabiliti. Penangkapan CNY 100.00, di mana unit terkecil ialah fen, mencatatkan:
journal capture-<operation_id>, CNY
debit processor_receivable 10000
credit merchant_payable 10000Bayaran balik CNY 30.00 menambah jurnal pembalik:
journal refund-<operation_id>, CNY
debit merchant_payable 3000
credit processor_receivable 3000Setiap jurnal mempunyai sekurang-kurangnya dua entri serta jumlah debit dan kredit yang sama bagi setiap mata wang. journal_id dan rujukan operasi perniagaannya adalah unik. Transaksi yang memajukan keadaan berwibawa kepada CAPTURED atau bayaran balik yang berjaya turut memasukkan jurnal dan peristiwa outbox. Jika yuran, caj balik, atau pembayaran keluar pedagang memasuki skop, tambahkan akaun eksplisit dan entri baharu; jangan sekali-kali menulis semula entri lama. Baki diperoleh daripada entri atau dipercepatkan oleh unjuran yang boleh dibina semula. Unjuran tidak boleh menjadi sumber kebenaran (source of truth) wang.
Bayaran balik serentak terlebih dahulu menuntut kapasiti secara bersyarat pada baris pembayaran. Operasi baharu dan peningkatan dalam jumlah sedang berjalan hanya dibenarkan apabila captured_amount - refunded_amount - pending_refund_amount mencukupi. Kejayaan memindahkan jumlah daripada belum selesai kepada dibayar balik, kegagalan pasti melepaskannya, dan status tidak diketahui mengekalkan tempahan. Ini menghalang bayaran balik lain daripada melebihi had. Penyedia mungkin menguatkuasakan siling bayaran baliknya sendiri, tetapi batas tak varian tempatan tidak boleh bergantung pada sokongan luaran tersebut.
Langkah 7: Selaraskan percanggahan senyap dan pulihkannya dengan selamat
Laluan masa nyata tidak dapat membuktikan bahawa tiada apa-apa yang terlepas. Lapisan penyelarasan pertama menyelesaikan operasi UNKNOWN melalui rujukan penyedia atau kunci keidempotenan dan membandingkan jumlah, mata wang, jenis operasi, dan keadaan terminal. Lapisan kedua memuatkan laporan transaksi atau penyelesaian penyedia yang tidak boleh ubah setiap hari dan memadankan rujukan pembayaran, operasi, jurnal, dan pesanan. Lapisan ketiga memadankan kelompok penyelesaian penyedia dengan deposit bank sebenar dan membezakan jumlah yang belum diselesaikan, yuran, bayaran balik, dan caj balik.
Kelaskan percanggahan sebagai luaran-sahaja, kejayaan-dalaman/hilang-luaran, jumlah atau mata wang salah, keadaan basi, rujukan pendua, lejar tidak seimbang, atau item penyelesaian hilang. Percanggahan berisiko tinggi menyekat pelepasan baki pedagang yang terjejas dan mencetuskan amaran. Pembaikan adalah idempoten: mengimport operasi penyedia yang telah disahkan menambah jurnal baharu dengan sebab audit, manakala pembetulan perakaunan menggunakan jurnal pampasan dan bukannya UPDATE pada sejarah. Dokumentasi pelaporan Stripe menerangkan transaksi baki sebagai tidak boleh ubah, dengan transaksi bayaran balik baharu membatalkan fakta asal, dan secara berasingan menyelaraskan pembayaran, kelompok pembayaran keluar, serta resit bank.
Metrik memisahkan kejayaan API dan p99, pengedaran keadaan pembayaran, bilangan dan usia operasi UNKNOWN, ralat dan pendikit (throttling) penyedia, kegagalan tandatangan/pendua/kelewatan webhook, masa pengesahan-ke-penangkapan, kapasiti bayaran balik yang ditempah, tunggakan outbox dan giliran, jurnal tidak seimbang yang ditolak, bilangan percanggahan, dan percanggahan tertua yang belum diselesaikan. Pelaporan perniagaan memastikan kadar pengesahan, penangkapan, bayaran balik, dan penyelesaian sentiasa dibezakan. "Permintaan diterima" tidak boleh dikira sebagai "wang diterima."
Langkah 8: Meminimumkan permukaan sensitif dan suntik kegagalan
Komponen penokenan penyedia mengumpul data kad secara langsung. Backend hanya menyimpan token penyedia yang tidak boleh diterbalikkan dan medan paparan yang diluluskan seperti jenama dan empat digit terakhir. Rahsia klien tidak pernah dimasukkan ke dalam URL atau log. Kunci penyedia disimpan dan digilirkan dalam sistem rahsia terkawal. Rahsia webhook adalah berasingan, serta persekitaran sandbox dan pengeluaran diasingkan. Melihat pembayaran, memulakan bayaran balik, membaca lejar, dan melakukan pembaikan manual menggunakan kebenaran yang berasingan. Setiap tindakan berisiko tinggi merekodkan pengendali dan sebabnya.
PCI SSC secara eksplisit melarang pengekalan kod pengesahan kad, PIN, dan blok PIN selepas pengesahan, walaupun disulitkan. Pengumpulan yang dihoskan mengecilkan pendedahan skop ini, tetapi penilaian rasmi masih menentukan pematuhan. Jawapan temu bual tidak boleh mendakwa bahawa "menggunakan token menghapuskan PCI."
Ujian penerimaan merangkumi klien yang mencuba semula kunci yang sama dan menukar jumlah di bawah kunci tersebut; kejayaan penyedia dengan respons yang hilang; ketibaan webhook sebelum respons API; webhook pendua, disusun semula, dan ditangguhkan; penerbitan outbox pendua; pengesahan berlumba dengan pembatalan; dua bayaran balik bersaing untuk kapasiti yang sama; bayaran balik penuh selepas bayaran balik sebahagian; tamat tempoh keidempotenan penyedia; penggiliran rahsia webhook; penolakan jurnal sebelah pihak; transaksi luaran-sahaja yang ditemui melalui penyelarasan; pelaksanaan pembaikan berulang; dan pemulihan selepas gangguan giliran atau penyedia yang berpanjangan. Setiap senario menegaskan keadaan pembayaran, keadaan operasi, bilangan jurnal, kesan sampingan pesanan, dan amaran.
Contoh Jawapan Berkualiti Tinggi
"Saya akan memodelkan pembayaran sebagai sumber perniagaan jangka panjang dan bukannya satu panggilan HTTP. Satu pesanan mempunyai payment_id yang stabil. Agregat menyimpan jumlah, mata wang, dan keadaan pengesahan/penangkapan/bayaran balik. Setiap pengesahan, penangkapan, pembatalan, dan bayaran balik menggunakan ID operasi yang berasingan serta PENDING, SUCCEEDED, FAILED, atau UNKNOWN. Tamat masa luaran menjadi UNKNOWN; ia tidak boleh menggagalkan proses serta-merta atau menukar penyedia.
Penciptaan pembayaran dan setiap operasi wang memerlukan kunci keidempotenan pemanggil. Pedagang, jenis operasi, dan kunci adalah unik. Permintaan pertama secara atomik menyimpan ringkasannya, pembayaran atau operasi, dan outbox; permintaan yang sama memainkan semula hasilnya, manakala jumlah atau mata wang yang berbeza di bawah kunci tersebut menghasilkan konflik. Pekerja menggunakan ID operasi dalaman sebagai kunci penyedia. Outbox, giliran, dan pekerja semuanya sekurang-kurangnya sekali, dan operasi yang sama menggunakan satu peralihan berwibawa.
Respons segerak penyedia, webhook yang disahkan tandatangannya, dan carian aktif memasuki fungsi aplikasi keadaan yang sama. Webhook mengesahkan muatan mentah, menyahduplikasi ID peristiwanya, mengekalkannya sebelum mengembalikan 2xx, dan bertoleransi terhadap penduaan serta penyusunan semula. Peristiwa lama tidak boleh menggerakkan pembayaran ke belakang. Pelayar hanya memaparkan keadaan tempatan dan tidak boleh mencetuskan pemenuhan pesanan. Hanya kejayaan penangkapan berwibawa yang dikomit bersama jurnal seimbang dan outbox perniagaan membolehkan perkhidmatan pesanan memenuhi pesanan secara idempoten.
Jurnal penangkapan mendebit akaun belum terima pemproses dan mengkredit akaun belum bayar pedagang. Bayaran balik menambah jurnal pembalik; sejarah adalah tidak boleh ubah. Penciptaan bayaran balik secara bersyarat menempah nilai boleh dibayar balik yang tersedia, supaya bayaran balik yang disahkan ditambah bayaran balik yang sedang berjalan tidak pernah melebihi penangkapan. Wang menggunakan unit terkecil integer, mata wang tidak boleh diubah selepas percubaan pertama, dan setiap mata wang diimbangi secara bebas.
Pemulihan mempunyai tiga lapisan: operasi tidak diketahui menggunakan semula kunci penyedia atau menyoal status, laporan penyedia harian menyelaraskan pembayaran, operasi, dan jurnal, dan kelompok penyelesaian dipadankan dengan deposit bank. Percanggahan dikuarantin dan diberi amaran; pembaikan hanya menambah import idempoten atau jurnal pampasan. Komponen penyedia yang dihoskan mengumpul kad, jadi backend tidak menyimpan nombor kad mahupun kod keselamatan. Respons yang hilang, webhook pendua atau disusun semula, penangkapan dan bayaran balik serentak, gangguan penyedia, jurnal tidak seimbang, dan item penyelarasan luaran-sahaja membuktikan bahawa setiap hasil luaran menumpu kepada satu fakta wang yang boleh diaudit."
Kesilapan Biasa
- Menganggap halaman kejayaan pelayar sebagai kejayaan pembayaran → pengalihan boleh dipalsukan, dan pembayaran mungkin masih menunggu pengesahan atau pengesahan tak segerak → Hanya bukti penyedia berwibawa yang diterima oleh mesin keadaan tempatan boleh mencetuskan pemenuhan pesanan.
- Menggunakan satu medan
paiduntuk keseluruhan kitaran hayat → ia tidak dapat menyatakan pengesahan tambahan, pengesahan, penangkapan, bayaran balik sebahagian, atau hasil yang tidak diketahui → Pisahkan agregat pembayaran daripada percubaan operasi. - Mencuba semula dengan ID baharu atau penyedia lain selepas tamat masa → percubaan pertama mungkin telah mengenakan caj, mewujudkan caj berganda → Gunakan semula operasi dan kunci penyedia, kemudian buat pertanyaan atau selaraskan hasil yang tidak diketahui.
- Membandingkan kunci keidempotenan sahaja, bukan parameter → pemanggil yang menggunakan semula kunci dengan jumlah yang diubah mendapat hasil perniagaan yang salah → Kekalkan ringkasan permintaan ternormal dan hasilkan konflik terhadap niat yang diubah.
- Bergantung pada urutan webhook → penyedia boleh mencuba semula, menangguhkan, dan menyusun semula peristiwa → Nyahduplikasi dan dapatkan keadaan semasa atau gunakan hanya peralihan monotonik yang dibenarkan.
- Menganggap baki jadual pembayaran sebagai lejar → kemas kini di tempat asal menghilangkan sebab perubahan wang dan tidak boleh diselaraskan secara bebas → Tambahkan jurnal yang seimbang; simpan baki sebagai unjuran yang boleh dibina semula.
- Membaca kemudian menulis baki boleh dibayar balik secara serentak → dua pemanggil boleh melihat kapasiti dan melebihi jumlah penangkapan → Tempah kapasiti dengan kemas kini bersyarat transaksi yang terikat secara unik pada operasi.
- Memantau respons API 200 sahaja → diterima, disahkan, ditangkap, dan diselesaikan mempunyai maksud yang berbeza → Ukur setiap keadaan, usia operasi tidak diketahui, dan percanggahan penyelarasan.
- Mendakwa penokenan menghapuskan tanggungjawab PCI secara automatik → halaman, log, skrip, dan proses operasi boleh kekal dalam skop → Meminimumkan data kad dan minta pihak pematuhan mengesahkan sempadan sebenar.
- Menyunting entri sejarah untuk membaiki percanggahan → rantaian audit terputus dan laporan sejarah tidak boleh dimainkan semula → Tambahkan import yang dijelaskan atau jurnal pampasan.
Soalan Susulan dan Respons
Susulan 1: Penyedia telah menangkap bayaran, tetapi kedua-dua respons segerak dan webhook telah hilang. Apakah yang berlaku?
Operasi kekal UNKNOWN, mengekalkan pengesahan berkaitan atau tempahan bayaran balik dan menghalang operasi lain untuk niat yang sama. Mula-mula cuba semula carian yang disokong atau buat panggilan dengan kunci keidempotenan penyedia asal, kemudian buat pertanyaan aktif mengikut rujukan penyedia. Jika ia masih tidak dapat ditentukan, tunggu penyelarasan laporan transaksi. Kejayaan yang disahkan memasuki fungsi aplikasi keadaan yang sama dan mencatatkan jurnal serta outbox; hanya kegagalan yang disahkan akan melepaskan kapasiti. Selepas pengekalan kunci penyedia tamat tempoh tanpa bukti, hantar kes tersebut kepada pengendali dan bukannya membuat kesimpulan kegagalan berdasarkan masa yang berlalu.
Susulan 2: Dua bayaran balik CNY 60 menyasarkan penangkapan CNY 100 secara serentak. Bagaimanakah anda menghalang terlebih bayar balik?
Gunakan kemas kini bersyarat pada pembayaran atau baris baki boleh dibayar balik yang dikhaskan. Ia meningkatkan pending_refund_amount sebanyak CNY 60 dan mencipta operasi hanya jika sekurang-kurangnya CNY 60 masih ada. Kedua-dua transaksi bersaing pada satu versi, jadi satu daripadanya berjaya dan satu lagi membaca semula kapasiti yang tidak mencukupi. Bayaran balik yang tidak diketahui mengekalkan tempahannya, kegagalan pasti melepaskannya, dan kejayaan memindahkan baki belum selesai kepada dibayar balik. Penguatkuasaan oleh penyedia hanyalah benteng pertahanan kedua.
Susulan 3: CAPTURED tiba melalui webhook sebelum AUTHORIZED. Bagaimanakah ia diproses?
Kekalkan dan nyahduplikasi kedua-dua resit. Jika tandatangan, jumlah, mata wang, dan rujukan penyedia CAPTURED sepadan, gunakan peralihan penangkapan dan catatkan jurnal. Peristiwa AUTHORIZED yang tiba kemudian ialah fakta lama. Mesin keadaan menolak pengembalian semula (rollback) dan hanya mengemas kini audit webhook serta metrik kelewatan. Jika muatan tidak mempunyai bukti versi yang mencukupi, dapatkan sumber pembayaran semasa penyedia dan bukannya menulis ganti mengikut susunan ketibaan.
Susulan 4: Mengapakah perlu mempunyai kedua-dua jadual pembayaran dan lejar?
Jadual pembayaran ialah agregat aliran kerja yang sesuai untuk menjawab sama ada penangkapan, pembatalan, atau bayaran balik dibenarkan. Lejar tambah-sahaja ialah rekod wang yang sesuai untuk menerangkan cara baki terbentuk dan peristiwa perniagaan mana yang menyebabkan setiap perubahan. Pembayaran boleh beralih daripada CAPTURED kepada PARTIALLY_REFUNDED, manakala lejar mengekalkan penangkapan asal dan setiap jurnal bayaran balik seimbang yang bebas. Rujukan operasi yang unik menggabungkan kedua-duanya, dan peralihan berwibawa mengkomit kedua-duanya dalam satu transaksi tempatan. Tiada satu pun tanggungjawab yang menggantikan yang lain.
Susulan 5: Bagaimanakah anda membuktikan bahawa pembaiki penyelarasan tidak boleh mencatat dua kali?
Berikan setiap baris laporan luaran kunci sumber yang stabil seperti penyedia, jenis laporan, dan rujukan transaksi. Ikatkan pembaikan kepada ID percanggahan dan tambahkan kekangan unik (source_key, repair_type). Transaksi pertama menambah jurnal, menandakan percanggahan, dan menulis outbox. Keranapan dan larian semula akan menemui pembaikan yang sama dan memainkan semula hasilnya. Hentikan (kill) proses sebelum komit, selepas komit, dan selepas penerbitan peristiwa; bilangan jurnal, baki, dan bilangan peristiwa hiliran tidak boleh meningkat untuk kali kedua.
Susulan 6: Jika penyedia kedua ditambah kemudian, bilakah failover dibenarkan?
Cipta operasi pada penyedia kedua hanya apabila penyedia pertama menyatakan secara eksplisit bahawa operasi tersebut tidak pernah dicipta atau gagal secara muktamad, dan operasi tempatan tidak mempunyai fakta wang. Tamat masa sambungan, 5xx, dan status tidak diketahui tidak memenuhi syarat tersebut. Audit pilihan penghalaan, keupayaan penyedia, jumlah, mata wang, dan sebab. Jika kedua-dua hasil mungkin wujud, bekukan pemenuhan pesanan dan pelepasan baki sementara pertanyaan dan penyelarasan menghapuskan kemungkinan caj berganda. Bayaran balik automatik tidak boleh menyembunyikan hasil yang tidak diketahui.