ഒരിക്കലും ബുക്കിംഗായി മാറാത്ത ഒരു വിജയകരമായ പേയ്മെന്റ്
ഒരു ഉപഭോക്താവ് പണമടച്ചു. Razorpay വിജയം കാണിച്ചു. Webhook ഒരു HTTP 200 അയച്ചു. പേയ്മെന്റ് ക്യാപ്ചർ ചെയ്യപ്പെട്ടു.
എന്നിട്ടും ബുക്കിംഗ് "confirming" എന്ന അവസ്ഥയിൽ തന്നെ തങ്ങിനിന്നു.
തെറ്റുകൾ (errors) ഒന്നും കാണിച്ചില്ല. കോഡിൽ യാതൊരു എക്സെപ്ഷനുകളും (exceptions) ഉണ്ടായില്ല. അലേർട്ടുകൾ ഒന്നും വന്നില്ല. എല്ലാ മെട്രിക്സുകളും സിസ്റ്റം കൃത്യമായി പ്രവർത്തിക്കുന്നു എന്നാണ് കാണിച്ചത്.
എന്നാൽ ഉപഭോക്താവിന് ഒന്നും ലഭിച്ചില്ല. ക്രിയേറ്റർക്ക് ബുക്കിംഗ് ലഭിച്ചതുമില്ല.
പണം സ്വീകരിക്കുന്നത് എളുപ്പമാണ്. ഓരോ പേയ്മെന്റും ഒരു ബുക്കിംഗിലേക്ക് നയിക്കുന്നുണ്ടെന്ന് ഉറപ്പാക്കുന്നതാണ് യഥാർത്ഥ വെല്ലുവിളി.
മിക്ക ട്യൂട്ടോറിയലുകളും ഈ രീതിയാണ് നിർദ്ദേശിക്കുന്നത്:
- Webhook ഇവന്റ് സ്വീകരിക്കുന്നു
- Webhook ബുക്കിംഗ് അപ്ഡേറ്റ് ചെയ്യുന്നു
ഇത് അപകടകരമാണ്. ബിസിനസ് ലോജിക് (business logic) വെബ്ഹുക്കിനുള്ളിൽ (webhook) ആണെങ്കിൽ, ഡെലിവറി വിജയത്തെ മാത്രം നിങ്ങൾ ആശ്രയിക്കുന്നു. വെബ്ഹുക്കുകൾക്ക് റീട്രൈകൾ (retries), ഡ്യൂപ്ലിക്കേറ്റുകൾ (duplicates), ഭാഗികമായ പരാജയങ്ങൾ (partial failures) എന്നിവ നേരിടേണ്ടി വരാറുണ്ട്.
ഈ ജോലികൾ വേർതിരിക്കുന്നതിനായി ഞങ്ങൾ ഞങ്ങളുടെ ആർക്കിടെക്ചറിൽ മാറ്റം വരുത്തി. വെബ്ഹുക്കുകൾ ഇപ്പോൾ ഇവന്റുകൾ മാത്രം രേഖപ്പെടുത്തുന്നു. അവ ബിസിനസ് ലോജിക് പ്രവർത്തിപ്പിക്കുന്നില്ല.
മൂന്ന് ടേബിളുകളുള്ള ഒരു ഇവന്റ് ലെഡ്ജർ (event ledger) ഞങ്ങൾ അവതരിപ്പിച്ചു:
- payment_orders: പ്രൊവൈഡറുടെ വിവരങ്ങൾ (The provider truth)
- payment_events: മാറ്റം വരുത്താൻ കഴിയാത്ത ഇവന്റ് ലെഡ്ജർ (The immutable event ledger)
- bookings: ബിസിനസ് വിവരങ്ങൾ (The business truth)
വെബ്ഹുക്കിന് ഇപ്പോൾ ഒരു ജോലി മാത്രമേയുള്ളൂ:
- സിഗ്നേച്ചർ പരിശോധിക്കുക (Verify signature)
- ഇവന്റ് സ്റ്റോർ ചെയ്യുക
- 200 റിട്ടേൺ ചെയ്യുക
ഇത് സിസ്റ്റത്തെ സംരക്ഷിക്കുന്നു. വെബ്ഹുക്ക് പരാജയപ്പെട്ടാലും ഇവന്റ് സുരക്ഷിതമായിരിക്കും.
പേയ്മെന്റ് സ്റ്റേറ്റും (payment state) ബുക്കിംഗ് സ്റ്റേറ്റും (booking state) വ്യത്യസ്തമാണെന്ന് ഞങ്ങൾ മനസ്സിലാക്കി. ക്യാപ്ചർ ചെയ്ത പേയ്മെന്റ് ഒരു ഇൻപുട്ട് ആണ്. കൺഫേം ചെയ്ത ബുക്കിംഗ് അതിന്റെ ഫലമാണ്. ഇവ രണ്ടും വേർതിരിച്ചു നിർത്തുന്നത് റീകൺസിലിയേഷന് (reconciliation) സഹായിക്കുന്നു.
ഒരു അന്വേഷണത്തിനിടെ ഞങ്ങൾ ഒരു ബഗ് (bug) കണ്ടെത്തി. ഇവന്റുകൾ ഡാറ്റാബേസിൽ ഉണ്ടായിരുന്നു. പ്രോസസ്സർ കൃത്യമായി പ്രവർത്തിക്കുന്നുണ്ടായിരുന്നു. വെബ്ഹുക്ക് കൃത്യമായി പ്രവർത്തിക്കുന്നുണ്ടായിരുന്നു.
എന്നാൽ പ്രോസസ്സർ ഒരിക്കലും പ്രവർത്തിച്ചില്ല. പെൻഡിംഗ് ഇവന്റുകൾ പ്രോസസ്സ് ചെയ്യുന്നതിനുള്ള ഫംഗ്ഷൻ ആരും ട്രിഗർ ചെയ്തിരുന്നില്ല.
ഇൻജഷനും (ingestion) പ്രോസസ്സിംഗും (processing) വേർതിരിക്കുന്നത് നല്ലൊരു ഡിസൈൻ ആണ്. എന്നാൽ ഇത് പുതിയൊരു ആവശ്യം ഉണ്ടാക്കുന്നു: പ്രോസസ്സിംഗ് ട്രിഗർ ചെയ്യാൻ എന്തെങ്കിലും വേണം.
പല ജോലികളും പ്രവർത്തിപ്പിക്കാൻ ഞങ്ങൾ ഒരു ഷെഡ്യൂളർ (scheduler) നടപ്പിലാക്കി:
- പേയ്മെന്റ് ഇവന്റുകൾ പ്രോസസ്സ് ചെയ്യുക
- വിട്ടുപോയ വെബ്ഹുക്കുകൾ വീണ്ടെടുക്കുക
- സിസ്റ്റം കൺസിസ്റ്റൻസി പരിശോധിക്കുക
റീട്രൈകൾക്കിടയിൽ തെറ്റുകൾ ഒഴിവാക്കാൻ ഞങ്ങൾ ഈ ലോജിക് ഉപയോഗിക്കുന്നു:
- പ്രോസസ്സ് ചെയ്യാത്ത ഇവന്റുകൾ തിരഞ്ഞെടുക്കുക
- ഒന്നിലധികം വർക്കർമാരെ അനുവദിക്കാൻ "SKIP LOCKED" ഉപയോഗിക്കുക
- ഡ്യൂപ്ലിക്കേറ്റ് ഡെലിവറികൾ ഒന്നും ചെയ്യുന്നില്ലെന്ന് ഉറപ്പാക്കുക
ഓരോ വെബ്ഹുക്കും കൃത്യസമയത്ത് ലഭിക്കുമ്പോൾ മാത്രം പ്രവർത്തിക്കുന്ന ഒരു സിസ്റ്റം ദുർബലമാണ് (fragile). നിങ്ങളുടെ ക്യൂവിൽ (queue) അത് ശൂന്യമാക്കാൻ ആരുമില്ലെങ്കിൽ, ജോലികൾ എന്നെന്നേക്കുമായി കാത്തുനിൽക്കും.
വിശ്വാസ്യത (Reliability) എന്നാൽ കാര്യങ്ങൾ പരാജയപ്പെടുമ്പോൾ അതിനെ നേരിടാൻ തയ്യാറെടുത്ത് നിർമ്മിക്കുക എന്നാണ് അർത്ഥം.