एक यशस्वी पेमेंट जे कधीच बुकिंगमध्ये रूपांतरित झाले नाही
एका ग्राहकाने पैसे भरले. Razorpay ने यश दाखवले. Webhook ने HTTP 200 पाठवला. पेमेंट कॅप्चर झाले होते.
तरीही बुकिंग "confirming" या स्थितीतच अडकून राहिले.
कोणतेही एरर दिसले नाहीत. कोडमध्ये कोणतीही एक्सेप्शन (exceptions) आली नाही. कोणतेही अलर्ट्स आले नाहीत. प्रत्येक मेट्रिकनुसार सिस्टम व्यवस्थित (healthy) दिसत होती.
पण ग्राहकाला काहीच मिळाले नाही. क्रिएटरकडे कोणतेही बुकिंग नव्हते.
पैसे स्वीकारणे सोपे आहे. प्रत्येक पेमेंटचे बुकिंगमध्ये रूपांतर होईल याची खात्री करणे हे खरे आव्हान आहे.
बहुतेक ट्युटोरियल्स हा फ्लो सुचवतात:
- Webhook इव्हेंट प्राप्त करते
- Webhook बुकिंग अपडेट करते
हे धोकादायक आहे. जर बिझनेस लॉजिक (business logic) Webhook च्या आत असेल, तर तुम्ही पूर्णपणे डिलिव्हरीच्या यशावर अवलंबून असता. Webhooks मध्ये रिट्रायज (retries), डुप्लिकेट्स (duplicates) आणि अंशतः अपयश (partial failures) यांसारख्या समस्या येऊ शकतात.
आम्ही या कामांना वेगळे करण्यासाठी आमची आर्किटेक्चर (architecture) बदलली. आता Webhooks फक्त इव्हेंट्स रेकॉर्ड करतात. ते बिझनेस लॉजिक कार्यान्वित करत नाहीत.
आम्ही तीन टेबल्ससह एक इव्हेंट लेजर (event ledger) सुरू केले:
- payment_orders: प्रोव्हायडरची सत्यता (The provider truth)
- payment_events: अपरिवर्तनीय इव्हेंट लेजर (The immutable event ledger)
- bookings: बिझनेसची सत्यता (The business truth)
आता Webhook चे एकच काम आहे:
- सिग्नेचर व्हेरिफाय करणे (Verify signature)
- इव्हेंट स्टोअर करणे (Store event)
- 200 रिटर्न करणे (Return 200)
हे सिस्टमला सुरक्षित ठेवते. जर Webhook फेल झाले, तरी इव्हेंट सुरक्षित असतो.
आम्हाला हे देखील समजले की पेमेंट स्टेट (payment state) आणि बुकिंग स्टेट (booking state) या वेगवेगळ्या आहेत. कॅप्चर केलेले पेमेंट हे एक इनपुट आहे. कन्फर्म केलेले बुकिंग हे त्याचे रिझल्ट आहे. त्यांना वेगळे ठेवल्यामुळे रिकॉन्सिलिएशन (reconciliation) करणे सोपे होते.
तपासादरम्यान आम्हाला एक बग (bug) आढळला. इव्हेंट्स डेटाबेसमध्ये अस्तित्वात होते. प्रोसेसर व्यवस्थित (healthy) होता. Webhook देखील व्यवस्थित होता.
पण प्रोसेसर कधीच चालला नाही. प्रलंबित (pending) इव्हेंट्स प्रोसेस करण्यासाठी फंक्शन ट्रिगर करणारे कोणीही नव्हते.
इनजेशन (ingestion) आणि प्रोसेसिंग (processing) वेगळे करणे हे एक चांगले डिझाइन आहे. पण यामुळे एक नवीन गरज निर्माण होते: प्रोसेसिंग ट्रिगर करण्यासाठी काहीतरी आवश्यक असते.
आम्ही काही जॉब्स चालवण्यासाठी एक शेड्युलर (scheduler) लागू केला:
- पेमेंट इव्हेंट्स प्रोसेस करणे
- मिस झालेले वेबहुक्स रिकव्हर करणे
- सिस्टमची सुसंगतता (consistency) तपासणे
रिट्रायज दरम्यान एरर टाळण्यासाठी, आम्ही ही लॉजिक वापरतो:
- अनप्रोसेस्ड (unprocessed) इव्हेंट्स निवडा
- मल्टिपल वर्कर्सना परवानगी देण्यासाठी "SKIP LOCKED" वापरा
- डुप्लिकेट डिलिव्हरीमुळे काहीही बदल होणार नाही याची खात्री करा
अशी सिस्टम जी फक्त प्रत्येक Webhook वेळेवर आल्यावरच काम करते, ती अत्यंत नाजूक (fragile) असते. जर तुमच्या क्यू (queue) मधून डेटा काढण्यासाठी कोणीही नसेल, तर काम कायमचे प्रलंबित राहते.
रिलायबिलिटी (Reliability) म्हणजे गोष्टी अयशस्वी झाल्यावरही काम करेल असे सिस्टम तयार करणे.