CRUD ऐप्स में रेस कंडीशन्स डुप्लिकेट ऑर्डर और गलत टोटल्स पैदा कर सकती हैं। सामान्य टकराव बिंदु और constraints, locks, और UX गार्ड्स से व्यावहारिक समाधानों को जानें।

रेस कंडीशन तब होती है जब दो (या अधिक) रिक्वेस्ट लगभग एक साथ उसी डेटा को अपडेट करती हैं और अंतिम परिणाम समय पर निर्भर करता है। हर रिक्वेस्ट अपने आप में सही दिखती है, लेकिन साथ में वे गलत परिणाम दे सकती हैं।
एक साधारण उदाहरण: दो लोग एक ही ग्राहक रिकॉर्ड पर एक सेकंड के भीतर Save दबाते हैं। एक ईमेल बदलता है, दूसरा फोन नंबर। अगर दोनों पूरा रिकॉर्ड भेजते हैं, तो दूसरी write पहली को ओवरराइट कर सकती है और एक बदलाव बिना किसी एरर के गायब हो जाता है।
यह तेज़ ऐप्स में अधिक दिखता है क्योंकि उपयोगकर्ता प्रति मिनट अधिक क्रियाएँ ट्रिगर कर सकते हैं। यह भी ऊपर चढ़ता है जब ट्रैफ़िक ज़्यादा हो: फ्लैश सेल, महीने के अंत की रिपोर्टिंग, बड़ी ईमेल मुहिम, या जब अनुरोधों का बैकलॉग एक ही पंक्तियों पर आ जाता है।
उपयोगकर्ता शायद ही कभी "रेस कंडीशन" रिपोर्ट करते हैं। वे लक्षण बताते हैं: डुप्लिकेट ऑर्डर या कमेंट, गायब अपडेट ("मैंने सेव किया था, पर वापस आ गया"), अजीब टोटल्स (इन्वेंटरी नेगेटिव हो जाना, काउंटर उल्टा कूदना), या स्टेटस जो अनपेक्षित रूप से पलटते हैं (स्वीकृत, फिर फिर से पेन्डिंग)।
रीट्राइज़ इसे और बुरा कर देती हैं। लोग डबल-क्लिक करते हैं, धीमे रिस्पॉन्स पर रिफ्रेश करते हैं, दो टैब से सबमिट करते हैं, या फ्लेकी नेटवर्क की वजह से ब्राउज़र और मोबाइल ऐप्स फिर से भेज देते हैं। अगर सर्वर हर रिक्वेस्ट को एक नई write माने तो आप दो क्रिएट, दो पेमेंट, या दो स्टेटस चेंज पा सकते हैं जो एक बार होने चाहिए थे।
अधिकतर CRUD ऐप्स सादे लगते हैं: एक रो पढ़ो, एक फ़ील्ड बदलो, सेव करो। मुद्दा यह है कि आपका ऐप टाइमिंग को नियंत्रित नहीं करता। डेटाबेस, नेटवर्क, रिट्राई, बैकग्राउंड वर्क और उपयोगकर्ता व्यवहार सब ओवरलैप करते हैं।
एक सामान्य ट्रिगर है: दो लोग एक ही रिकॉर्ड को एडिट कर रहे होते हैं। दोनों एक ही "current" वैल्यूज़ लोड करते हैं, दोनों वैध बदलाव करते हैं, और आख़िरी सेव चुपचाप पहली को ओवरराइट कर देता है। किसी ने जानबूझकर कुछ गलत नहीं किया, पर एक अपडेट खो जाता है।
यह एक ही व्यक्ति के साथ भी होता है। Save बटन पर डबल-क्लिक, धीमा कनेक्शन जो दोबारा सबमिट करवा दे, या एक फ़ोन जो दो टैप रजिस्टर कर दे—ऐसी स्थितियों में वही write दो बार भेजा जा सकता है। अगर endpoint idempotent नहीं है, तो आप डुप्लिकेट बना सकते हैं, दो बार चार्ज कर सकते हैं, या स्टेटस दो कदम आगे बढ़ सकता है।
आधुनिक उपयोग और भी अधिक ओवरलैप जोड़ता है। एक ही अकाउंट में कई टैब या डिवाइस कॉन्फ्लिक्टिंग अपडेट भेज सकते हैं। बैकग्राउंड जॉब्स (ईमेल, बिलिंग, सिंक, क्लीनअप) उन्हीं रोज़ को छू सकते हैं जो वेब रिक्वेस्ट छू रहे हैं। क्लाइंट, लोड बैलेंसर, या जॉब रनर पर ऑटोमेटिक रिट्राइज़ पहले से सफल रिक्वेस्ट को दोहरा सकते हैं।
अगर आप फीचर जल्दी दे रहे हैं, तो वही रिकॉर्ड अक्सर अलग-अलग जगहों से अपडेट होता है जितना कोई याद रखता है। अगर आप Koder.ai जैसे चैट-ड्रिवन बिल्डर का इस्तेमाल कर रहे हैं, तो ऐप और भी तेज़ी से बढ़ सकता है, इसलिए प्रतिस्पर्धा/कनकरेंसी को एक सामान्य व्यवहार समझें, न कि एक एज केस।
रेस कंडीशन्स आम तौर पर "रिकॉर्ड बनाओ" डेमो में नहीं दिखते। वे वहाँ दिखते हैं जहाँ दो रिक्वेस्ट एक ही सत्यापन (piece of truth) को लगभग एक साथ छूते हैं। सामान्य हॉटस्पॉट्स जानने से आप पहले दिन से सुरक्षित लिखने की योजना बना सकते हैं।
जो कुछ भी "बस +1 करो" जैसा है, वह लोड में टूट सकता है: लाइक्स, व्यू काउंट्स, टोटल्स, इनवॉयस नंबर, टिकट नंबर। रिस्की पैटर्न है: वैल्यू पढ़ो, जोड़ो, फिर वापस लिख दो। दो रिक्वेस्ट एक ही शुरुआती वैल्यू पढ़ कर एक-दूसरे को ओवरराइट कर सकती हैं।
Draft -> Submitted -> Approved -> Paid जैसे वर्कफ़्लो सीधी दिखते हैं, पर कोलाइज़न सामान्य हैं। समस्या तब शुरू होती है जब एक समय पर दो क्रियाएँ संभव हों (approve और edit, cancel और pay)। बिना गार्ड्स के आप ऐसे रिकॉर्ड पा सकते हैं जो स्टेप्स स्किप कर देते हैं, वापस पलटते हैं, या अलग-अलग तालिकाओं में अलग स्टेट्स दिखाते हैं।
स्टेटस चेंज को एक कॉन्ट्रैक्ट की तरह ट्रीट करें: केवल अगला वैध स्टेप ही अनुमति दें और बाकी को अस्वीकार कर दें।
बचे हुए सीट्स, स्टॉक काउंट्स, अपॉइंटमेंट स्लॉट्स और "रिमेनिंग कैपेसिटी" वाले फ़ील्ड क्लासिक ओवरसेल समस्या बनाते हैं। दो खरीदार एक ही समय में चेकआउट करते हैं, दोनों को उपलब्धता दिखती है, और दोनों सफल हो जाते हैं। अगर डेटाबेस अंतिम निर्णायक नहीं है, तो अंततः आप अपनी क्षमता से ज़्यादा बेच देंगे।
कुछ नियम अनिवार्य होते हैं: एक खाता पर एक ईमेल, एक उपयोगकर्ता पर एक सक्रिय सब्सक्रिप्शन, एक उपयोगकर्ता पर एक खुला कार्ट। ये अक्सर उस समय फेल होते हैं जब आप पहले चेक करते हैं ("क्या कोई मौजूद है?") और फिर insert करते हैं। कनकरेंसी में दोनों रिक्वेस्ट चेक पास कर सकती हैं।
अगर आप जल्दी CRUD फ्लोज बना रहे हैं (उदाहरण के लिए Koder.ai से), इन हॉटस्पॉट्स को शुरुआत में लिख लें और इन्हें सिर्फ UI चेक से नहीं, बल्कि कंस्ट्रेंट्स और सुरक्षित लिखावट से बैक करें।
कई रेस कंडीशन्स एक बोरिंग कारण से शुरू होती हैं: वही एक्टिविटी दो बार भेज दी जाती है। यूज़र डबल-क्लिक करते हैं। नेटवर्क स्लो होने पर वे फिर से क्लिक करते हैं। कभी-कभी यह जानबूझकर नहीं होता: पेज एक POST के बाद रिफ्रेश होता है और ब्राउज़र फॉर्म को फिर से सबमिट करने की पेशकश करता है।
ऐसा होने पर, आपका बैकएंड समानांतर में दो क्रिएट या अपडेट चला सकता है। अगर दोनों सफल होते हैं, तो आपको डुप्लिकेट, गलत टोटल्स, या स्टेटस चेंज जो दो बार चला (उदाहरण: approve फिर से) मिल सकता है। यह यादृच्छिक लगता है क्योंकि यह टाइमिंग पर निर्भर करता है।
सबसे सुरक्षित तरीका है रक्षा की परतें (defense in depth)। UI ठीक करो, पर मानो कि UI फेल भी होगी।
अधिकांश लिखने के फ्लो में लागू करने योग्य व्यावहारिक परिवर्तन:
उदाहरण: एक उपयोगकर्ता मोबाइल पर "Pay invoice" पर दो बार टैप करता है। UI को दूसरे टैप को ब्लॉक करना चाहिए। सर्वर को भी दूसरी रिक्वेस्ट को अस्वीकार करना चाहिए जब वह वही idempotency कुंजी देखे, और मूल सफलता परिणाम लौटाए बजाय दो बार चार्ज करने के।
स्टेटस फ़ील्ड साधारण लगते हैं जब तक दो चीज़ें एक साथ उन्हें बदलने की कोशिश न करें। एक यूज़र Approve क्लिक करता है जबकि एक ऑटोमेटेड जॉब वही रिकॉर्ड Expired मार्क कर रहा होता है, या दो टीम सदस्य अलग-अलग टैब में एक ही आइटम पर काम कर रहे होते हैं। दोनों अपडेट सफल हो सकते हैं, पर अंतिम स्टेटस आपके नियमों पर नहीं बल्कि टाइमिंग पर निर्भर करेगा।
स्टेटस को एक छोटा स्टेट मशीन मानें। एक अलाउड मूव्स की सूचि रखें (उदाहरण के लिए: Draft -> Submitted -> Approved, और Submitted -> Rejected)। फिर हर write चेक करे: "क्या यह मूव वर्तमान स्टेटस से अलाउड है?" अगर नहीं, तो उसे रिजेक्ट करें बजाय चुपचाप ओवरराइट करने के।
ऑप्टिमिस्टिक लॉकिंग आपको stale अपडेट पकड़ने में मदद करती है बिना अन्य यूज़र्स को ब्लॉक किए। एक वर्शन नंबर (या updated_at) जोड़ें और सेव करते समय उसे मिलाना आवश्यक रखें। अगर किसी और ने शीघ्रता से रो बदल दिया है तो आपका अपडेट शून्य रो प्रभावित करेगा और आप एक साफ़ संदेश दिखा सकते हैं जैसे "यह आइटम बदल गया है, रिफ्रेश करके फिर कोशिश करें।"
स्टेटस अपडेट के लिए एक सरल पैटर्न:
साथ ही, स्टेटस चेंज को एक ही जगह रखें। अगर अपडेट्स अलग-अलग स्क्रीन, बैकग्राउंड जॉब्स और वेबहुक्स में बिखरे हुए हैं, तो आप एक नियम मिस कर देंगे। उन्हें एक फ़ंक्शन या एंडपॉइंट के पीछे रखें जो हर बार वही ट्रांज़िशन चेक लागू करे।
सबसे सामान्य काउंटर बग मासूम दिखता है: ऐप वैल्यू पढ़ता है, +1 करता है, फिर वापस लिख देता है। लोड में, दो रिक्वेस्ट एक ही नंबर पढ़ कर दोनों नई वैल्यू लिख देंगे, इसलिए एक इंक्रीमेंट खो जाता है। यह मिस करना आसान है क्योंकि यह "अधिकांश समय काम करता है" टेस्टिंग में।
अगर कोई वैल्यू सिर्फ increment या decrement हो रही है, तो डेटाबेस को एक स्टेटमेंट में करने दें। फिर डेटाबेस भारी कंसकरेंसी में भी बदलाव सुरक्षित रूप से लागू करेगा।
UPDATE posts
SET like_count = like_count + 1
WHERE id = $1;
इसी आइडिया को इन्वेंटरी, व्यू काउंट्स, रिट्राय काउंटर और किसी भी ऐसी चीज़ पर लागू करें जिसे "new = old + delta" के रूप में व्यक्त किया जा सके।
टोटल्स अक्सर तब गलत होते हैं जब आप किसी व्युत्पन्न संख्या (order_total, account_balance, project_hours) को स्टोर करते हैं और फिर कई जगहों से अपडेट करते हैं। अगर आप टोटल स्रोत रोज़ (line items, ledger entries) से गणना कर सकते हैं तो आप बहुत सी ड्रिफ्ट बग्स से बच जाते हैं।
जब आपको स्पीड के लिए टोटल स्टोर करना ही पड़े, तो उसे क्रिटिकल लिखावट समझें। स्रोत रोज़ और स्टोर किए गए टोटल को एक ही ट्रांज़ेक्शन में अपडेट रखें। सुनिश्चित करें कि एक ही समय में केवल एक राइटर उसी टोटल को अपडेट कर सके (लॉकिंग, गार्डेड अपडेट्स, या एकल मालिक पथ)। ऐसे मान जो असंभव हों उन्हें रोकने वाले constraints जोड़ें (उदाहरण: नेगेटिव इन्वेंटरी न हो)। फिर समय-समय पर बैकग्राउंड रीकॉनसिलिएशन करके मिसमैच फ्लैग करें।
एक ठोस उदाहरण: दो उपयोगकर्ता एक ही कार्ट में एक साथ आइटम जोड़ते हैं। अगर प्रत्येक रिक्वेस्ट cart_total पढ़ती है, अपनी आइटम प्राइस जोड़ती है और फिर लिख देती है, तो एक जोड़ गायब हो सकता है। अगर आप कार्ट आइटम और कार्ट टोटल को एक ही ट्रांज़ेक्शन में अपडेट करें, तो भारी पैरेलल क्लिक के बावजूद टोटल सही रहेगा।
अगर आप रेस कंडीशन्स कम करना चाहते हैं तो डेटाबेस से शुरू करें। ऐप कोड रिट्राई कर सकता है, टाइम आउट हो सकता है, या दो बार चल सकता है। एक डेटाबेस कंस्ट्रेंट आख़िरी द्वार है जो तब भी सही रहेगा जब दो रिक्वेस्ट एक साथ आएँ।
यूनिक कंस्ट्रेंट्स उन डुप्लिकेट्स को रोकते हैं जो "कभी नहीं होने चाहिए" पर होते हैं: ईमेल, ऑर्डर नंबर, इनवॉयस आईडी, या "प्रति उपयोगकर्ता एक ही सक्रिय सब्सक्रिप्शन"। जब दो साइनअप एक साथ आते हैं, डेटाबेस एक रो स्वीकार करता है और दूसरे को रिजेक्ट कर देता है।
फॉरेन कीज़ टूटी रेफरेंस को रोकती हैं। उनके बिना, एक रिक्वेस्ट पैरेंट रो को डिलीट कर सकता है जबकि दूसरी एक चाइल्ड रो बना देती है जो किसी चीज की तरफ इशारा नहीं करता—इससे ऑरफ़न रोज़ बनते हैं जो बाद में साफ करना मुश्किल होता है।
चेक कंस्ट्रेंट्स मानों को सुरक्षित सीमा में रखते हैं और साधारण स्टेट नियम लागू करते हैं। उदाहरण: quantity >= 0, rating 1 और 5 के बीच, या status को एक अलाउड सेट तक सीमित करना।
कंस्ट्रेंट फेल्यर्स को "एक्सपेक्टिड आउटकम" समझें, न कि "सर्वर एरर"। यूनिक, फॉरेन की और चेक वायलेशंस को पकड़ें, एक साफ़ संदेश लौटाएँ जैसे "यह ईमेल पहले से उपयोग में है," और डिबगिंग के लिए विवरण लॉग करें बिना इंटरनल लीक किए।
उदाहरण: लैग के दौरान दो लोग "Create order" दो बार क्लिक करते हैं। (user_id, cart_id) पर यूनिक कंस्ट्रेंट होने से आपको दो ऑर्डर नहीं मिलेंगे—आपको एक ऑर्डर और एक स्पष्ट, समझाने योग्य रिजेक्शन मिलेगा।
कुछ लिखावटें एक स्टेटमेंट नहीं होतीं। आप एक रो पढ़ते हैं, नियम चेक करते हैं, स्टेटस अपडेट करते हैं, और शायद एक ऑडिट लॉग डालते हैं। अगर दो रिक्वेस्ट यह सब एक साथ करें तो दोनों चेक पास कर सकते हैं और दोनों लिख सकते हैं। यही क्लासिक फेलियर पैटर्न है।
मल्टी-स्टेप लिखावट को एक डेटाबेस ट्रांज़ेक्शन में रैप करें ताकि सभी स्टेप्स साथ सफल हों या कोई भी न हो। सबसे महत्वपूर्ण बात, ट्रांज़ेक्शन आपको यह नियंत्रित करने का स्थान देता है कि एक ही समय में कौन वही डेटा बदल सकता है।
जब केवल एक अभिनेता एक रिकॉर्ड को एक समय में एडिट कर सकता है, तो रो-लेवल लॉक का उपयोग करें। उदाहरण: ऑर्डर रो लॉक करें, पुष्टि करें कि यह अभी भी "pending" है, फिर उसे "approved" पर फ्लिप करें और ऑडिट एंट्री लिखें। दूसरी रिक्वेस्ट वेट करेगी, फिर स्टेट चेक करके रुक जाएगी।
कॉलिशन कितनी बार होते हैं, उसके आधार पर चुनें:
लॉक का समय छोटा रखें। लॉक हो रहे समय में जितना कम काम हो उतना बेहतर: कोई बाहरी API कॉल नहीं, कोई धीमा फ़ाइल वर्क नहीं, कोई बड़ा लूप नहीं। अगर आप Koder.ai जैसे टूल में फ्लो बना रहे हैं, तो ट्रांज़ेक्शन को सिर्फ़ डेटाबेस स्टेप्स तक सीमित रखें, और बाकी काम कमिट के बाद करें।
ऐसा एक फ्लो चुनें जो कोलाइज़न होने पर पैसा या भरोसा खो दे—आम उदाहरण: ऑर्डर बनाओ, स्टॉक रिज़र्व करो, फिर ऑर्डर स्टेटस को confirmed पर सेट करो।
आज आपका कोड क्या कदम लेता है, क्रम में लिख दें। यह स्पष्ट बताएं कि क्या पढ़ा जा रहा है, क्या लिखा जा रहा है, और "सफलता" का अर्थ क्या है। कोलाइज़न पढ़ने और बाद के लिखने के बीच के गैप में छिपे होते हैं।
अधिकांश स्टैक्स में काम करने वाला हार्डनिंग पथ:
एक टेस्ट जोड़ें जो फिक्स को साबित करे। एक ही उत्पाद और मात्रा के खिलाफ एक साथ दो रिक्वेस्ट चलाएँ। सुनिश्चित करें कि ठीक एक ही ऑर्डर confirmed बनता है, और दूसरा नियंत्रित तरीके से फेल होता है (कोई नेगेटिव स्टॉक नहीं, कोई डुप्लिकेट रिज़र्वेशन रो नहीं)।
यदि आप जल्दी ऐप जेनरेट करते हैं (जिसमें Koder.ai जैसे प्लेटफ़ॉर्म भी शामिल हैं), तो ये चेकलिस्ट उन कुछ लिखावट पाथ्स पर लागू करें जो सबसे ज़्यादा मायने रखते हैं।
सबसे बड़ा कारण UI पर भरोसा करना है। डिसेबल बटन और क्लाइंट-साइड चेक मदद करते हैं, पर उपयोगकर्ता डबल-क्लिक कर सकते हैं, रिफ्रेश कर सकते हैं, दो टैब खोल सकते हैं, या रिक्वेस्ट को किसी फ्लेकी कनेक्शन से फिर से चला सकते हैं। अगर सर्वर idempotent नहीं है, तो डुप्लिकेट निकल आते हैं।
एक और शांत बग: आप डेटाबेस एरर (जैसे यूनिक कंस्ट्रेंट वायलेशन) पकड़ते हैं पर फिर भी वर्कफ़्लो जारी रखते हैं। इससे अक्सर होता है "create failed, पर हमने फिर भी ईमेल भेज दिया" या "payment failed, पर हमने ऑर्डर पेड मार्क कर दिया"। एक बार साइड एफेक्ट्स हो जाएं तो उन्हें उलटना मुश्किल होता है।
लंबे ट्रांज़ेक्शन्स भी जाल हैं। अगर आप ट्रांज़ेक्शन खुले रखते हुए ईमेल, पेमेंट या थर्ड-पार्टी APIs कॉल करते हैं तो आप ज़रूरत से ज़्यादा लॉक होल्ड कर रहे होते हैं। इससे वेटिंग, टाइमआउट और रिक्वेस्ट्स का एक-दूसरे को ब्लॉक करने का मौका बढ़ता है।
बैकग्राउंड जॉब्स और यूज़र ऐक्शन्स को एक ही सोर्स ऑफ ट्रूथ के बिना मिलाना स्प्लिट-ब्रेन स्टेट बनाता है। एक जॉब रिट्राई कर के रो अपडेट करता है जबकि एक यूज़र उसे एडिट कर रहा है, और अब दोनों सोचते हैं कि वे अंतिम लेखक थे।
कुछ "फिक्स" जो वास्तव में ठीक नहीं करते:
अगर आप Koder.ai से बना रहे हैं, तो वही नियम लागू होते हैं: सर्वर-साइड कंस्ट्रेंट्स और स्पष्ट ट्रांज़ेक्शनल सीमाएँ मांगें, सिर्फ़ बेहतर UI गार्ड्स नहीं।
रेस कंडीशन्स अक्सर असली ट्रैफ़िक में ही दिखते हैं। शिप से पहले एक पास सबसे आम कोलाइज़न पॉइंट पकड़ सकता है बिना री-राइट के।
डेटाबेस से शुरू करें। अगर कुछ यूनिक होना चाहिए (ईमेल, इनवॉयस नंबर, प्रति उपयोगकर्ता एक सक्रिय सब्सक्रिप्शन), तो इसे वास्तविक यूनिक कंस्ट्रेंट बनाएं, न कि ऐप-लेवल "पहले हम चेक करते हैं" नियम। फिर सुनिश्चित करें कि आपका कोड कंस्ट्रेंट के कभी-कभी फेल होने की उम्मीद करता है और एक साफ़, सुरक्षित प्रतिक्रिया लौटाता है।
अगला, स्टेट पर नज़र डालें। कोई भी स्टेटस चेंज (Draft -> Submitted -> Approved) एक स्पष्ट सेट ऑफ अलाउड ट्रांज़िशन्स के खिलाफ वैलिडेट होना चाहिए। अगर दो रिक्वेस्ट एक ही रिकॉर्ड को मूव करने की कोशिश करें तो दूसरी को रिजेक्ट या नो-ऑप होना चाहिए, न कि बीच का कुछ स्टेट बनाना चाहिए।
एक व्यावहारिक प्री-रिलीज चेकलिस्ट:
अगर आप Koder.ai में फ्लोज़ बना रहे हैं, तो इन्हें स्वीकृति मापदंड के रूप में रखें: जेनरेटेड ऐप को रिपीट और कनकरेंसी के तहत सुरक्षित तरीके से फेल करना चाहिए, न कि सिर्फ़ हैप्पी पाथ पास करना चाहिए।
दो स्टाफ सदस्य एक ही खरीद अनुरोध खोलते हैं। दोनों कुछ सेकंड के भीतर Approve पर क्लिक करते हैं। दोनों रिक्वेस्ट सर्वर पर पहुंचती हैं।
क्या गलत जा सकता है वह गड़बड़ है: अनुरोध दो बार "approved" हो सकता है, दो नोटिफिकेशन जा सकती हैं, और अप्रूवल से जुड़े कोई भी टोटल्स (बजट उपयोग, दैनिक अप्रूवल काउंट) 2 से कूद सकते हैं। दोनों अपडेट अपने आप में वैध हैं, पर वे टकरा रहे हैं।
यहाँ एक फिक्स प्लान है जो PostgreSQL-शैली डेटाबेस के साथ अच्छी तरह काम करता है।
एक नियम जोड़ें जो गारंटी दे कि किसी अनुरोध के लिए केवल एक अप्रूवल रिकॉर्ड मौजूद हो सकता है। उदाहरण के लिए, अप्रूवल्स को अलग तालिका में रखें और request_id पर UNIQUE कंस्ट्रेंट लागू करें। अब दूसरी insert ऐप कोड बग होने पर भी फेल हो जाएगी।
अप्रूव करते समय पूरा ट्रांज़ेक्शन करें:
अगर दूसरा स्टाफ मेंबर देरी से आता है, तो या तो उसे 0 रो अपडेट दिखेंगे या यूनिक-कंस्ट्रेंट एरर मिलेगा। किसी भी हालत में केवल एक परिवर्तन जीतेगा।
फिक्स के बाद, पहला स्टाफ मेंबर Approved देखेगा और सामान्य कन्फर्मेशन मिलेगा। दूसरा स्टाफ मेंबर एक दोस्ताना संदेश देखेगा जैसे: "यह अनुरोध पहले ही किसी और ने अप्रूव कर दिया है। नवीनतम स्टेटस देखने के लिए रिफ्रेश करें।" कोई स्पिनिंग नहीं, कोई डुप्लिकेट नोटिफिकेशन नहीं, कोई चुप्पी में फेल्यर नहीं।
अगर आप Koder.ai में CRUD फ्लो जेनरेट कर रहे हैं (Go बैकएंड के साथ PostgreSQL), तो आप इन चेक्स को approve एक्शन के अंदर एक बार बनाकर अन्य "एक ही विजेता" कार्रवाइयों के लिए पुन: उपयोग कर सकते हैं।
रेस कंडीशन्स को ठीक करना आसान तब होता है जब आप उन्हें एक दोहराने योग्य रूटीन मानते हैं, न कि एक-बार का बग हंट। उन कुछ राइट पाथ्स पर ध्यान दें जो सबसे ज़्यादा मायने रखते हैं, और उन्हें भद्दा सही (boringly correct) बना दें इससे पहले कि आप कुछ और पॉलिश करें।
शुरुआत करें—अपने शीर्ष कोलाइज़न पॉइंट्स का नाम लिखकर। कई CRUD ऐप्स में यह वही तिकड़ी होती है: काउंटर (लाइक्स, इन्वेंटरी, बैलेंस), स्टेटस चेंज (Draft -> Submitted -> Approved), और डबल सबमिट (डबल-क्लिक, रिट्राइज़, स्लो नेटवर्क)।
एक टिकाऊ रूटीन जो काम करता है:
अगर आप Koder.ai पर बना रहे हैं, तो Planning Mode एक व्यावहारिक जगह है जहाँ आप हर write फ्लो को स्टेप्स और नियमों के रूप में मैप कर सकते हैं, इससे पहले कि आप Go और PostgreSQL में कोड जेनरेट करें। स्नैपशॉट्स और रोलबैक भी उपयोगी हैं जब आप नए कंस्ट्रेंट्स या लॉक व्यवहार शिप कर रहे हों और किसी एज केस पर जल्दी वापस जाना चाहें।
समय के साथ, यह एक आदत बन जाएगी: हर नए राइट फीचर के साथ एक कंस्ट्रेंट, एक ट्रांज़ेक्शन प्लान और एक कनकरेंसी टेस्ट जोड़ा जाएगा। इस तरह CRUD ऐप्स में रेस कंडीशन्स हैरानी नहीं रहेंगी।