सिंक्रोनस रिक्वेस्ट/रिस्पॉन्स पर सोचना आसान है। सर्विस ए सर्विस बी को कॉल करती है, इंतज़ार करती है, जवाब या एरर मिलता है। यह मॉडल तब टूटता है जब एक एक्शन कई स्वतंत्र सिस्टमों तक फैलना चाहिए, जब वे अलग-अलग दर से स्केल करते हैं, या जब एक निर्भरता का अस्थायी आउटेज पूरे चेकआउट पथ को नहीं रोकना चाहिए।

इवेंट-ड्रिवन आर्किटेक्चर कॉन्ट्रैक्ट बदल देता है: प्रोड्यूसर उस बात का तथ्य प्रकाशित करता है जो पहले ही हो चुकी, और कंज़्यूमर अपने समय पर प्रतिक्रिया देते हैं। आपको डीकपलिंग और हॉरिज़ॉन्टल स्केल मिलता है। कीमत है इवेंटुअल कंसिस्टेंसी, कठिन डिबगिंग, और ऐसे फेलियर मोड जो एक ही स्टैक ट्रेस में नहीं दिखते।

यह पोस्ट उच्च-माँग सिस्टम पर बैकएंड इंजीनियरों के लिए ज़रूरी विचारों का नक्शा है: इवेंट/कमांड विभाजन, ब्रोकर, आइडेम्पोटेंट कंज़्यूमर, आउटबॉक्स पैटर्न, और वे मामले जहाँ इवेंट गलत औज़ार हैं।


«इवेंट-ड्रिवन» वास्तव में क्या है

इवेंट-ड्रिवन डिज़ाइन में कंपोनेंट इवेंट जारी करके और उन पर प्रतिक्रिया देकर बात करते हैं, आमतौर पर मैसेज ब्रोकर या लॉग के ज़रिए। प्रोड्यूसर नहीं जानते कौन कंज़्यूम करता है। कंज़्यूमर उसी तथ्य के लिए प्रोड्यूसर को वापस कॉल नहीं करते। कपलिंग «मुझे तुम्हारा एपीआई जानना और कॉल करते समय ऑनलाइन होना चाहिए» से बदलकर «हमें मैसेज स्कीमा और डिलीवरी देर या डुप्लिकेट होने पर रिकवरी पर सहमत होना चाहिए» हो जाती है।

उच्च-माँग की आम आकृतियाँ:

आकृति उदाहरण इवेंट क्यों मदद करते हैं
राइट के बाद फैन-आउट ऑर्डर लगा → इन्वेंटरी, ईमेल, एनालिटिक्स, लॉयल्टी एक राइट, कई स्वतंत्र साइड इफेक्ट
असिंक हैंडऑफ़ अपलोड पूरा → वायरस स्कैन → थंबनेल → सर्च इंडेक्स धीमा काम रिक्वेस्ट पथ छोड़ देता है
इंटीग्रेशन पेमेंट वेबहुक → लेजर + नोटिफिकेशन बाहरी सिस्टम अपने शेड्यूल पर आते हैं
स्ट्रीम प्रोसेसिंग क्लिक स्ट्रीम → फ्रॉड स्कोर → फीचर स्टोर निरंतर, ऊँचा वॉल्यूम, प्रति आइटम कम काम

इवेंट का मतलब नहीं है «हर एचटीटीपी एपीआई को कतार से बदल दो।» ज्यादातर सिस्टम हाइब्रिड रहते हैं: उपयोगकर्ता-सामने रीड/राइट के लिए सिंक्रोनस जहाँ तुरंत जवाब चाहिए, और बाद में पूरा होने वाले काम के लिए असिंक्रोनस।


इवेंट बनाम कमांड

लोग इन दोनों को मिला देते हैं। ये अलग कॉन्ट्रैक्ट हैं।

इवेंट: वह तथ्य जो हो चुका

इवेंट भूतकाल में होता है और प्रकाशित होने के बाद अपरिवर्तनीय। प्रोड्यूसर पहले ही स्टेट चेंज कमिट कर चुका (या कम से कम तय कर चुका कि तथ्य सही है)। कंज़्यूमर कर सकते हैं:

  • अपने मॉडल अपडेट करना
  • वर्कफ़्लो ट्रिगर करना
  • अप्रासंगिक होने पर इवेंट नज़रअंदाज़ करना

उदाहरण:

{
  "type": "OrderPlaced",
  "eventId": "evt_01J8K2...",
  "occurredAt": "2026-02-04T10:15:30Z",
  "orderId": "ord_9f3a",
  "customerId": "cus_12",
  "totalCents": 4599,
  "currency": "USD"
}

नाम भूतकाल में रखें: OrderPlaced, PaymentCaptured, UserEmailChanged। पेलोड में इतना डेटा होना चाहिए कि कंज़्यूमर हर फ़ील्ड के लिए प्रोड्यूसर को वापस कॉल किए बिना काम कर सकें (उचित सीमा में)। केवल आईडी वाले पतले इवेंट लोड में हर कंज़्यूमर को चैटी रीड पथ पर धकेलते हैं।

कमांड: कुछ करने का निर्देश

कमांड आज्ञासूचक है। भेजने वाला चाहता है कि एक खास रिसीवर कोई एक्शन करे। इसे स्वीकार, अस्वीकार, या विफल किया जा सकता है। परिणाम अभी तथ्य नहीं है।

उदाहरण: PlaceOrder, ChargeCard, ReserveInventory

कमांड अक्सर कतारों पर चलते हैं, एक तार्किक कंज़्यूमर ग्रुप (या ज्ञात वर्कर प्रकार) के साथ। इवेंट अक्सर टॉपिक पर जाते हैं, कई स्वतंत्र सब्सक्राइबर के साथ।

इवेंट कमांड
काल भूत (OrderPlaced) आज्ञासूचक (PlaceOrder)
परिणाम का स्वामित्व प्रोड्यूसर पहले तय कर चुका हैंडलर तय करता है
कपलिंग प्रोड्यूसर कंज़्यूमर नहीं जानता भेजने वाला एक ज़िम्मेदारी को निशाना बनाता है
फैन-आउट स्वाभाविक (कई सब्सक्राइबर) आमतौर पर एक हैंडलर प्रकार
विफलता कंज़्यूमर अपना काम रिट्राई करते हैं कमांड अस्वीकार / क्षतिपूर्ति कर सकती है

व्यावहारिक रूप से, सफल कमांड हैंडलर अक्सर इवेंट जारी करता है। PlaceOrder सफल → OrderPlaced प्रकाशित। यह विभाजन राइट इरादे और तथ्य के प्रसार को अलग रखता है।


ब्रोकर और लॉग: आप असल में क्या खरीद रहे हैं

ब्रोकर (या लॉग) प्रोड्यूसर और कंज़्यूमर के बीच साझा इंफ्रा है। प्रोडक्ट चुनाव उस डिलीवरी सेमांटिक्स से कम मायने रखता है जिसके लिए आप डिज़ाइन करते हैं।

आम विकल्प (मानसिक मॉडल, बेक-ऑफ नहीं)

सिस्टम मॉडल अच्छा डिफ़ॉल्ट
काफ़्का / रेडपाँडा अपेंड-ओनली लॉग, कंज़्यूमर ऑफ़सेट, पार्टिशन ऊँचा थ्रूपुट, रीप्ले, कई कंज़्यूमर ग्रुप
रैबिटएमक्यू कतार, एक्सचेंज, राउटिंग की वर्क कतार, जटिल राउटिंग, कम वॉल्यूम
एसक्यूएस (+ एसएनएस) प्रबंधित कतार / फैन-आउट एडब्ल्यूएस-नेटिव वर्कर, सरल ऑप्स
नैट्स / जेटस्ट्रीम हल्का मैसेजिंग + वैकल्पिक पर्सिस्टेंस कम लेटेंसी, सरल टोपोलॉजी
गूगल पब/सब प्रबंधित टॉपिक/सब्सक्रिप्शन जीसीपी-नेटिव इवेंट फैन-आउट

डिलीवरी गारंटी जिनके साथ जीना है

लगभग हर प्रोडक्शन ब्रोकर उन फेलियर पथों पर एट-लीस्ट-वन्स देता है जो मायने रखते हैं। कंज़्यूमर प्रोसेस करने के बाद और एकॉलेज से पहले क्रैश हो सकता है। वही मैसेज वापस आता है।

इसके लिए डिज़ाइन करें:

१. आधार रेखा के रूप में एट-लीस्ट-वन्स। २. आइडेम्पोटेंट कंज़्यूमर (अगला खंड)। ३. ऑर्डर केवल जहाँ ज़रूरत हो (आमतौर पर प्रति एग्रीगेट कुंजी, जैसे orderId), पूरे सिस्टम पर ग्लोबल ऑर्डर नहीं। ४. रिटेंशन / रीप्ले अगर कंज़्यूमर फिर बनाना हो या बग से उबरना हो।

«एग्जैक्टली-वन्स» मार्केटिंग आमतौर पर ट्रांजेक्शनल प्रोड्यूसर, आइडेम्पोटेंट कंज़्यूमर, और ब्रोकर फीचर का सावधान संयोजन है। इसे पूरे पाइपलाइन की संपत्ति मानें, प्रोडक्ट पेज के चेकबॉक्स की नहीं।

टॉपिक, पार्टिशन और कुंजियाँ

लॉग-आधारित सिस्टमों के लिए:

  • एक एंटिटी के लिए क्रमबद्ध रहने वाले इवेंट एक ही पार्टिशन कुंजी पर रखें (जैसे orderId)।
  • पार्टिशन संतुलित रखें। एक गरम कुंजी एक गरम पार्टिशन बन जाती है।
  • सार्वजनिक इंटीग्रेशन टॉपिक (स्थिर स्कीमा) को आंतरिक टॉपिक से अलग रखें जिन्हें आप ज़्यादा आज़ादी से तोड़ सकते हैं।

कतार-आधारित सिस्टमों के लिए:

  • समानांतर प्रोसेसिंग के लिए वर्क कतार पर कंपिटिंग कंज़्यूमर पसंद करें।
  • एन विफलताओं के बाद जहरीले मैसेज के लिए डेड-लेटर कतार (डीएलक्यू) उपयोग करें।
  • कॉनकरेंसी सीमित रखें ताकि स्पाइक वर्कर के पीछे डेटाबेस को न पिघला दे।

आइडेम्पोटेंसी: कंज़्यूमर डुप्लिकेट देखेंगे

अगर एक ही संचालन नियम याद रखना हो: हर कंज़्यूमर को वही इवेंट दो बार सहन करना चाहिए

डुप्लिकेट तब आते हैं जब:

  • क्रैश या नेटवर्क ब्लिप के बाद ब्रोकर फिर डिलीवर करता है
  • प्रोड्यूसर ऐसे पब्लिश को रिट्राई करता है जो असल में सफल हो चुका
  • बग फिक्स के बाद आप पार्टिशन रीप्रोसेस करते हैं
  • एट-लीस्ट-वन्स धीमे एकॉलेज से मिलता है

व्यावहारिक पैटर्न

१. साइड इफेक्ट से पहले आइडेम्पोटेंसी कुंजी संग्रहीत

मैसेज से स्थिर आईडी लें (eventId, या प्राकृतिक कुंजी जैसे paymentId + status)। अपने राइट के साथ एक ही डेटाबेस ट्रांजेक्शन में:

INSERT INTO processed_events (event_id, consumer, processed_at)
VALUES ($1, 'inventory-service', now())
ON CONFLICT (event_id, consumer) DO NOTHING;
-- if insert did nothing, skip business work

अगर इन्सर्ट जीतता है, उसी ट्रांजेक्शन में बिज़नेस बदलाव लागू करें। अगर हारता है, आप यह इवेंट पहले ही संभाल चुके।

२. डोमेन में प्राकृतिक आइडेम्पोटेंसी

कुछ राइट स्वभाव से दोहराने योग्य सुरक्षित हैं:

  • SET status = 'shipped' WHERE order_id = $1 AND status = 'paid'
  • समान पेलोड के साथ प्राइमरी कुंजी पर अपसर्ट
  • «हमेशा बढ़ाओ» की जगह «गैरहाज़िर हो तो जोड़ो»

जब फिट हो, डोमेन चेक चुनें। हर सूक्ष्म-अपडेट के लिए विशाल साइड टेबल से वे साफ़ पढ़े जाते हैं।

३. आउटबाउंड साइड इफेक्ट (ईमेल, वेबहुक, चार्ज)

बाहरी एपीआई कठिन हिस्सा हैं। दूसरी भेजत डबल-चार्ज या स्पैम कर सकती है।

  • जिन प्रोवाइडर में सपोर्ट हो, क्लाइंट रिक्वेस्ट आईडी / आइडेम्पोटेंसी कुंजी पास करें (पेमेंट एपीआई अक्सर देते हैं)।
  • आंशिक विफलता के स्पष्ट नियम के साथ कॉल से पहले या बाद «इस इवेंट के लिए नोटिफिकेशन पहले भेजी» दर्ज करें।
  • कंज़्यूमर लूप में फायर-एंड-फॉरगेट के बजाय «एक बार भेजो» टेबल पसंद करें।

क्या न करें

«ब्रोकर ने एग्जैक्टली वन्स कहा» पर भरोसा न करें। मल्टी-इंस्टेंस कंज़्यूमर पर केवल इन-मेमोरी «मैंने यह देखा» सेट न इस्तेमाल करें। मैसेज क्रम को आइडेम्पोटेंसी का विकल्प न मानें; लोड में रीऑर्डरिंग और रीडिलीवरी दोनों होते हैं।


डुअल-राइट समस्या और आउटबॉक्स

क्लासिक विफलता यह है:

1. BEGIN; INSERT order; COMMIT;
2. publish OrderPlaced to broker

अगर कदम २ कमिट के बाद फेल हो, ऑर्डर मौजूद है और कोई कंज़्यूमर नहीं सुनता। अगर क्रम उलटें और पब्लिश के बाद डेटाबेस राइट फेल हो, कंज़्यूमर भूत ऑर्डर प्रोसेस करते हैं।

अधिकांश ब्रोकर पर उसी डेटाबेस ट्रांजेक्शन में पब्लिश उपलब्ध नहीं। दो स्वतंत्र सिस्टम बिना मदद के एक एटॉमिक कमिट साझा नहीं कर सकते।

ट्रांजेक्शनल आउटबॉक्स

बिज़नेस पंक्ति और आउटबॉक्स पंक्ति एक ही डेटाबेस ट्रांजेक्शन में लिखें। अलग प्रक्रिया (या सीडीसी) आउटबॉक्स पंक्तियाँ ब्रोकर पर प्रकाशित करती है, फिर भेजी गई चिह्नित करती है।

BEGIN;

INSERT INTO orders (id, customer_id, total_cents, status)
VALUES ($1, $2, $3, 'placed');

INSERT INTO outbox (id, aggregate_type, aggregate_id, event_type, payload, created_at)
VALUES ($4, 'order', $1, 'OrderPlaced', $5::jsonb, now());

COMMIT;

रिले लूप (सरलीकृत):

1. SELECT pending outbox rows (FOR UPDATE SKIP LOCKED)
2. publish to broker
3. mark published_at (or delete)

वे गुण जो चाहिए:

चिंता दृष्टिकोण
स्टेट + पब्लिश इरादे की एटॉमिसिटी एक ही डेटाबेस ट्रांजेक्शन
कमिट के बाद खोए इवेंट नहीं पब्लिश सफल होने तक रिले रिट्राई
कॉनकरेंसी में फँसी पंक्तियाँ नहीं SKIP LOCKED, बैच आकार सीमा
डुप्लिकेट पब्लिश फिर भी संभव कंज़्यूमर आइडेम्पोटेंट रहें
ऑब्ज़र्वेबिलिटी आउटबॉक्स लैग मेट्रिक, सबसे पुराना अनभेजा आयु

आउटबॉक्स के रूप में सीडीसी

चेंज डेटा कैप्चर (डेबेज़ियम आदि) डेटाबेस लॉग का पीछा करता है और पंक्ति बदलाव को इवेंट बनाता है। वही विचार: स्रोत सत्य कमिट लॉग है, कमिट के बाद ऐप का बेस्ट-एफर्ट पब्लिश नहीं। स्कीमा, फ़िल्टर, और कंज़्यूमर आइडेम्पोटेंसी फिर भी डिज़ाइन करें।

इनबॉक्स (वैकल्पिक दर्पण)

कुछ टीमें कंज़्यूमर पक्ष पर इनबॉक्स टेबल भी इस्तेमाल करती हैं, «मैंने इवेंट एक्स प्राप्त किया» का टिकाऊ स्टोर, फिर वहाँ से प्रोसेस। वही थीम: «हैंडल किया» मार्कर को डोमेन राइट के साथ ट्रांजेक्शनल रखें।


विफलता, रिट्राई, और ज़हरीले मैसेज

उच्च-माँग सिस्टम आंशिक तरीकों से फेल होते हैं। कंज़्यूमर लूप ऐसे डिज़ाइन करें मानो हर निर्भरता टाइमआउट कर सकती है।

१. क्षणिक एरर (डेटाबेस लॉक, नेटवर्क ब्लिप) के लिए बैकऑफ़ के साथ रिट्राई। प्रयासों की सीमा रखें। २. एन विफलताओं के बाद डीएलक्यू, ताकि एक खराब पेलोड पार्टिशन या कतार हमेशा के लिए न रोके। ३. डीएलक्यू गहराई और आउटबॉक्स लैग पर अलर्ट। चुप लैग ज़ोरदार विफलता से बदतर है। ४. हैंडलर छोटे रखें। लंबे हैंडलर मध्य-उड़ान रीडिलीवरी का मौका बढ़ाते हैं। ५. जब हो सके «इवेंट प्रोसेस» को «नाज़ुक थर्ड पार्टी कॉल» से अलग करें: तेज़ प्रोसेस करें, नाज़ुक कॉल के लिए अलग जॉब कतार में डालें।

काफ़्का-शैली लॉग पर, ज़हरीले मैसेज पर अटका कंज़्यूमर पूरा पार्टिशन रोक सकता है। इसलिए स्केल पर डीएलक्यू (या सावधानी से स्किप-एंड-मेट्रिक) वैकल्पिक नहीं।


स्कीमा और विकास

बिना कॉन्ट्रैक्ट के ढीला जेएसओएन तीसरे कंज़्यूमर के बाद प्रोडक्शन दर्द बन जाता है।

व्यावहारिक नियम:

  • इवेंट प्रकार या स्कीमा वर्शन करें (OrderPlaced.v1, या schemaVersion फ़ील्ड)।
  • योगात्मक बदलाव चुनें: नए वैकल्पिक फ़ील्ड। नाम बदलना या फ़ील्ड का अर्थ मोड़ना टालें।
  • जब कई टीमें टॉपिक साझा करें, रजिस्ट्री (एवरो/प्रोटोबफ़/जेएसओएन स्कीमा) उपयोग करें।
  • दस्तावेज़ करें कौन से फ़ील्ड सहीपन के लिए आवश्यक हैं बनाम सुविधा डीनॉर्मलाइज़ेशन।
  • इवेंट पेलोड में सीक्रेट न डालें। इवेंट अक्सर रखे जाते हैं और संगठन में व्यापक रूप से पढ़े जाते हैं।

जब ब्रेकिंग बदलाव अपरिहार्य हो, कुछ समय डुअल-पब्लिश चलाएँ या नया टॉपिक खड़ा करें और कंज़्यूमर जान-बूझकर माइग्रेट करें।


कब इवेंट-ड्रिवन डिज़ाइन न इस्तेमाल करें

इवेंट ट्रेड-ऑफ़ हैं, पदोन्नति नहीं। तब छोड़ें या सीमित रखें जब:

स्थिति इसके बजाय चुनें
उपयोगकर्ता को उसी रिक्वेस्ट में तुरंत सही जवाब चाहिए सिंक्रोनस एपीआई + डेटाबेस ट्रांजेक्शन
एक टीम एक डिप्लॉयएबल रखती है और फैन-आउट नहीं इन-प्रोसेस कॉल या मॉड्यूलर मोनोलिथ
एक क्लिक में कई एग्रीगेट पर मज़बूत कंसिस्टेंसी चाहिए एक ट्रांजेक्शन सीमा, या सगा तभी जब जटिलता स्वीकार हो
टीम के पास ब्रोकर, लैग मेट्रिक, डीएलक्यू, स्कीमा समीक्षा का ऑप्स नहीं प्लंबिंग चला सकने तक सरल आर्किटेक्चर
डिबगिंग कौशल पतला और ट्रैफ़िक कम एंड-टू-एंड ट्रेस आसान रिक्वेस्ट/रिस्पॉन्स
केवल रात की रिपोर्ट चाहिए बैच जॉब, रीयल-टाइम टॉपिक नहीं

«काफ़्का पर वितरित मोनोलिथ» भी टालें: हर सर्विस को एक उपयोगकर्ता एक्शन पूरा करने के लिए बाकी सभी के इवेंट अभी भी चाहिए, बिना स्पष्ट स्वामित्व। वितरित सिस्टम के फेलियर मोड मिलते हैं, आइसोलेशन के लाभ नहीं।

उपयोगी परीक्षण: अगर ब्रोकर १० मिनट खोने से कोर प्रोडक्ट अनुपयोगी हो जाए, केवल साइड इफेक्ट देर न हों, तो शायद क्रिटिकल पथ लॉजिक गलत ट्रांसपोर्ट पर रखी है।


न्यूनतम प्रोडक्शन चेकलिस्ट

उच्च-माँग फ़्लो पर इवेंट पथ शिप करने से पहले:

१. इवेंट बनाम कमांड सही नाम और स्वामित्व के साथ। २. स्कीमा दस्तावेज़ीकृत; कंज़्यूमर आवश्यक फ़ील्ड जानते हैं। ३. प्रोड्यूसर आउटबॉक्स (या सीडीसी) उपयोग करता है, डुअल-राइट आशा नहीं। ४. कंज़्यूमर एट-लीस्ट-वन्स डिलीवरी के लिए आइडेम्पोटेंट है। ५. अगर मायने रखे तो ऑर्डर प्रति कुंजी परिभाषित; ग्लोबल नहीं माना। ६. रिट्राई + डीएलक्यू + लैग अलर्ट मौजूद और परीक्षित। ७. बैकप्रेशर: रीप्ले या ट्रैफ़िक स्पाइक पर कंज़्यूमर और डेटाबेस पूल नहीं पिघलेंगे। ८. बग के बाद एक दिन के इवेंट रीप्रोसेस का तरीका पता हो, बिना उपयोगकर्ता को डबल-चार्ज किए।


समापन

इवेंट-ड्रिवन आर्किटेक्चर तब जगह कमाता है जब स्वतंत्र सिस्टम एक ही तथ्यों पर अलग गति से प्रतिक्रिया दें, और जब रिक्वेस्ट पथ हर साइड इफेक्ट का इंतज़ार न कर सकें। इंजीनियरिंग लागत वास्तविक है: ब्रोकर, स्कीमा, आइडेम्पोटेंसी, आउटबॉक्स, और लैग मॉनिटरिंग फीचर का हिस्सा हैं, अतिरिक्त नहीं।

एक स्पष्ट तथ्य (OrderPlaced), एक आउटबॉक्स, एक आइडेम्पोटेंट कंज़्यूमर, और लैग मेट्रिक से शुरू करें। तभी बढ़ाएँ जब अगला फैन-आउट सिंक्रोनस कॉल से ज़्यादा दुख दे, नए सब्सक्राइबर से कम। यह क्रम उच्च-माँग सिस्टम लचीले रखता है, बिना हर राइट को वितरित रहस्य बनाए।