खतरनाक अनुरोध पहला नहीं है। वही अनुरोध फिर आता है, क्योंकि भेजने वाले ने पहला जवाब नहीं सुना, या सुनकर भी फिर कोशिश की। भुगतान प्रदाता ऐसा करते हैं। कतारें ऐसा करती हैं। ब्राउज़र तब ऐसा करता है जब कोई बटन दो बार दबाए। अगर सिस्टम दूसरी प्रति को नया काम माने, आप दो बार चार्ज करेंगे, दो बार भेजेंगे, या एक दांव पर बही की दो पंक्तियाँ लिखेंगे।
डुप्लिकेट मानकर चलें
मैं हैंडलर ऐसा बनाता हूँ कि दूसरी डिलीवरी एक सफलता हो जो कुछ न करे। पहली काम करती है और एक कुंजी रखती है: प्रदाता की इवेंट id, या क्लाइंट की भेजी कुंजी, डेटाबेस में अनोखी। दूसरी कुंजी पाकर वही परिणाम लौटाती है। दूसरा चार्ज नहीं। दूसरा ईमेल नहीं। दूसरी पंक्ति नहीं।
यूनिक कंस्ट्रेंट वही हिस्सा है जिस पर मैं भरोसा करता हूँ। इंसर्ट से एक पल पहले एप्लिकेशन कोड की जाँच उस दौड़ में हार जाती है जब दो worker एक साथ जागते हैं। डेटाबेस वह दौड़ नहीं हारता। हारने वाले को संघर्ष मिलता है और वह उसे “पहले ही हो चुका” बना देता है।
| पहली आवक | दूसरी आवक | |
|---|---|---|
| खोज | कुंजी नई है | कुंजी पहले से सहेजी है |
| लिखना | एक पंक्ति, एक साइड इफेक्ट | नई पंक्ति नहीं |
| जवाब | स्वीकृत | वही, पहले से स्वीकृत |
| अगर प्रक्रिया बीच में मर जाए | आउटबॉक्स अभी संदेश का ऋणी है | दूसरा बकाया नहीं |
संदेश लिखने के साथ जाता है, या बिल्कुल नहीं
ईमेल या कतार का संदेश अनुरोध के अंदर और commit से पहले भेजना वह तरीका है जिससे आपको उस लेनदेन का संदेश मिलता है जो वापस हो गया। मैं बाहर जाने वाला संदेश व्यवसाय पंक्ति के उसी लेनदेन में लिखता हूँ, और अलग worker उसे प्रकाशित करता है। प्रक्रिया मर जाए तो पंक्ति और संदेश दोनों हों या दोनों न हों। worker प्रकाशन दोहरा सकता है। हैंडलर चार्ज नहीं दोहराए।
वॉइड नई प्रविष्टि है, संपादन नहीं
जब कुछ पूर्ववत करना हो, मैं मूल पंक्ति के ऊपर नहीं लिखता। एक समायोजन प्रविष्टि बताती है क्या बदला, और पहली पंक्ति पढ़ने योग्य छोड़ती है। एक हफ्ते बाद भी आप बता सकते हैं 14:02 पर क्या माना गया था। पंक्ति बदलना केवल यह बताता है अभी क्या माना जाता है, और बिना गवाह के।
अगर दोबारा कोशिश ऑपरेशन को दो बार करा सकती है, तो ऑपरेशन खत्म नहीं हुआ।
हैंडलर लिखने से पहले कुंजी का नाम रखें
कुंजी “पूरे अनुरोध का हैश” नहीं है, जब तक आपने न देखा हो कि पुनः प्रयास के बीच भेजने वाला क्या बदलता है। भुगतान प्रदाता वही इवेंट id नई डिलीवरी समय-मुद्रा के साथ फिर भेजेगा। अगर वह मुद्रा कुंजी के अंदर है, दूसरी डिलीवरी नई लगेगी, और आपने वही बग बना लिया जिसे रोकना था। मैं वह id लेता हूँ जिसे भेजने वाला स्थिर बताता है। अगर वह एक न दे, मैं बुलाने वाले से एक भेजने को कहता हूँ, और बिना उसके आने वाली कॉल ठुकराता हूँ।
फिर मैं असफलता को सफलता वाली जगह लिखता हूँ। संघर्ष भेजने वाले के लिए त्रुटि पृष्ठ नहीं है। यह दोबारा कोशिश का अपेक्षित जवाब है। भेजने वाला रुक सके। अगर मैं 500 उत्तर दूँ, वे तीसरी बार कोशिश करेंगे, चौथी भी, और घटना एक जैसी काम की कतार बन जाएगी।
मैं इसे इसलिए पूरा नहीं मानता कि सुखद रास्ते ने 200 लौटाया। परीक्षण वही पेलोड फिर भेजता है और एक ही साइड इफेक्ट जाँचता है। फिर commit और प्रकाशन के बीच worker को मारता है और जाँचता है कि संदेश अभी भी एक बार निकलता है। ये दो परीक्षण उस घटना से छोटे हैं जिसकी जगह वे लेते हैं। मैं वहीं से शुरू करता हूँ।
