घटनाओं को दोहराते समय CRQS में दुष्प्रभावों को कैसे संभालें?


10

यह कहा जाता है कि CQRS में बग को ठीक करना आसान है, आप बस फिर से काम करते हैं और फिर घटनाओं को दोहराते हैं।

लेकिन, क्या होगा अगर घटनाओं में से एक बाहरी प्रणाली को आपके नियंत्रण में न रखें ताकि ग्राहक को "एक आइटम जहाज" करें यदि आप घटनाओं को फिर से दोहराते हैं तो आइटम को दो बार भेज दिया जाएगा।

आप इसका समाधान कैसे करेंगे?

जवाबों:


6

आपको अपने रीड मॉडल की स्थिति को संशोधित करने वाली घटनाओं और बाहरी सिस्टम की स्थिति को संशोधित करने वाली घटनाओं (संभावित) के बीच एक स्पष्ट अलगाव करने की आवश्यकता है। सुनिश्चित करें कि आपके पास दोनों राज्यों को एक साथ संशोधित करने की कोई "मिश्रित घटना" नहीं है। इस तरह, आप एक विशिष्ट "रीप्ले मोड" में अपनी घटनाओं को फिर से दोहरा सकते हैं जहां बाहरी सिस्टम के लिए उन घटनाओं को फिर से निकाल नहीं दिया जाता है। इस मोड में, आप किसी भी ईवेंट को "अनुकरण" करते हैं जो मूल रूप से बाहरी सिस्टम द्वारा शुरू किया गया था (अब आप उन्हें बजाय रिप्ले कतार से लेते हैं)।

मत भूलो, redeploy स्टेप का मतलब वास्तव में रीड मॉडल की स्थिति को पहले के समय में रीसेट करना है। यह शायद कुछ भी नहीं है जो आप कर सकते हैं (या करने की आवश्यकता है) बाहरी प्रणालियों की स्थिति के लिए।


"मत भूलो, redeploy चरण का अर्थ वास्तव में रीड मॉडल की स्थिति को पहले के समय में रीसेट करना है। यह संभवत: कुछ भी नहीं है जो आप बाहरी प्रणालियों की स्थिति के लिए कर सकते हैं (या करने की आवश्यकता है)।" -> लेकिन क्या होगा अगर मैं चाहता हूं कि मेरा रीप्ले शिपिंग जैसी असफल बाहरी प्रणाली कॉल को फिर से शुरू कर दे? इस मामले में मेरे पुन: प्रस्ताव में एक पुनरावृत्ति न केवल रीड मॉडल की स्थिति को रीसेट करेगा, बल्कि बाहरी घटनाओं का कारण भी होगा, क्या यह उचित लगता है या मुझे कुछ याद नहीं है?
जस

2
@ जज: आप एक असफल बाहरी सिस्टम कॉल को पुनः प्राप्त करने के लिए "रीप्ले" का दुरुपयोग नहीं करना चाहते हैं। आप अपने सिस्टम के रीड मॉडल को उसी राज्य में प्राप्त करने के लिए "रीप्ले" का उपयोग करते हैं, जो पहले था। इसका मतलब है कि विफल शिपिंग अनुरोध के मामले में, आपके सिस्टम को इस विफलता के बारे में सूचित किया गया था और उस जानकारी को उसके राज्य में कहीं संग्रहीत किया गया था। रिप्ले सुनिश्चित करता है कि यह जानकारी अभी भी है "aftereeploy & replay"। इसलिए रीप्ले के बाद, आपका सिस्टम "विफलता के मामले में रिट्रीट शिपिंग" लागू कर सकता है (जिसका CQRS से कोई लेना-देना नहीं है, किसी भी मजबूत आदेश प्रणाली के पास ऐसी रणनीति होनी चाहिए)।
डॉक ब्राउन

दिलचस्प है, यह वही है जो मुझे करने के लिए था, बस सोच रहा था कि क्या इस पर "पैटर्न" है इसलिए मैं पहिया को फिर से नहीं बढ़ाता हूं!
जस

3

मार्टिन फाउलर के इवेंट सोर्सिंग लेख से:

इवेंट सोर्सिंग का मूल विचार यह है कि किसी एप्लिकेशन की स्थिति में हर परिवर्तन को सुनिश्चित करने के लिए एक ईवेंट ऑब्जेक्ट में कैप्चर किया जाता है, और यह कि इन ईवेंट ऑब्जेक्ट्स को स्वयं उसी क्रम में संग्रहीत किया जाता है, जो वे उसी जीवनकाल के लिए लागू किए गए थे जैसे कि एप्लिकेशन स्टेट।

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

कहा जा रहा है, यदि आप केवल राज्य डेटा के साथ काम कर रहे हैं, तो बाहरी सिस्टम पर कोई प्रभाव नहीं होना चाहिए। जब तक आपके पास आपके ईवेंट स्टोर पर ट्रिगर या वॉचर्स नहीं होते हैं, तो जिस स्थिति में आपको उन्हें पुनर्स्थापित करने की अवधि के लिए अक्षम करना चाहिए। जब से आप कहते हैं कि बाहरी व्यवस्था पर आपका कोई नियंत्रण नहीं है, तब तक उजागर एपीआई का उपयोग करके इसके राज्य को पुनर्स्थापित करने का कोई प्रयास नहीं होना चाहिए क्योंकि आपको नहीं पता कि उनके सिस्टम में इसके क्या दुष्प्रभाव हो सकते हैं। यदि पुनर्स्थापना सिस्टम को एक मध्यवर्ती स्थिति में रखता है (उदाहरण के लिए बाहरी सिस्टम में विफल संचालन के कारण) यह एक इवेंट रीप्ले की जिम्मेदारियों के भीतर नहीं होना चाहिए।


2

लेकिन, क्या होगा अगर घटनाओं में से एक बाहरी प्रणाली को आपके नियंत्रण में न रखें ताकि ग्राहक को "एक आइटम जहाज" करें यदि आप घटनाओं को फिर से दोहराते हैं तो आइटम को दो बार भेज दिया जाएगा।

एक विशिष्ट उदाहरण चुनने के लिए, आइए विचार करें कि साइड इफेक्ट्स के लिए "कम से कम एक बार" दृष्टिकोण कैसे काम कर सकता है।

State currentState = State.InitialState
for(Event e : events) {
    currentState = currentState.apply(e)
}
for(SideEffect s : currentState.querySideEffects()) {
    performSideEffect(s)

इसलिए डोमेन मॉडल ट्रैक करता है कि क्या किया जाना चाहिए; लेकिन आवेदन करने के लिए वास्तविक कर छोड़ देता है

कमांड चलाने के संदर्भ में, मूल विचार समान है। वास्तविक साइड इफेक्ट मॉडल को अपडेट करने वाले लेनदेन के बाहर होता है ।

तो आपके मॉडल के लिए यूनिट परीक्षण कुछ ऐसा लग सकता है

{
    // Given
    State currentState = State.InitialState

    // When
    Events events = List.of(OrderPlaced)

    // Then
    List.of(SendEmail) === currentState.applyAll(events).querySideEffects()
}

{
    // Given
    State currentState = State.InitialState

    // When
    Events events = List.of(OrderPlaced, EmailSent)

    // Then
    List.EMPTY === currentState.applyAll(events).querySideEffects()
}

यहाँ मुख्य बिंदु हैं

  • मॉडल को अपडेट करना साइड इफेक्ट फ्री है; वास्तविक दुष्प्रभाव मॉडल को अद्यतन करने वाले लेनदेन के बाहर होता है।
  • साइड इफेक्ट के परिणाम का वर्णन करने वाली एक घटना को वापस आने की आवश्यकता है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.