DDD, Saga & การจัดหากิจกรรม: การกระทำแบบชดเชยสามารถลบในร้านค้าได้หรือไม่?


15

ฉันรู้ว่าคำถามข้างต้นอาจทำให้เกิดอะไรขึ้นบ้าง แต่ขอให้ฉันพยายามอธิบาย:

ฉันกำลังพยายามสรุปแนวคิดที่เกี่ยวข้องสองอย่างโดยทั่วไปแล้วรูปแบบ Saga ( http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf ) ร่วมกับ Event-sourcing (แนวคิด DDD) : http://en.wikipedia.org/wiki/Domain-driven_design )

โพสต์ที่ดีที่รวมเข้าด้วยกัน: https://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-ii-of-ii/

ฉันได้รับคำถามในหนึ่งนาที แต่ฉันคิดว่าฉันต้องพยายามสรุปสิ่งที่ฉันเข้าใจก่อน (ซึ่งอาจผิดพลาดได้โปรดแก้ไขให้ถูกต้องหากเป็นกรณีนี้) เนื่องจากสิ่งนี้อาจส่งผลกระทบต่อสาเหตุที่ฉัน ถามคำถามเพื่อเริ่มต้นด้วย:

  1. รูปแบบ Saga คือนายหน้าประเภทหนึ่งที่ให้การกระทำ (ผู้ใช้ปลายทางอัตโนมัติ ฯลฯ โดยพื้นฐานแล้วอะไรก็ตามที่กำลังจะเปลี่ยนข้อมูล) จะแบ่งการกระทำนั้นในกิจกรรมทางธุรกิจและส่งกิจกรรมเหล่านี้เป็นข้อความไปยัง Message Bus ซึ่ง ในทางกลับกันส่งไปยังรากรวมที่เกี่ยวข้องที่จะได้รับการดูแล
  2. รากรวมเหล่านี้สามารถทำงานได้อย่างสมบูรณ์แบบอัตโนมัติ (แยกความกังวล, ปรับขยายได้ดี ฯลฯ )
  3. Saga-instance นั้นไม่มีตรรกะทางธุรกิจใด ๆ ที่มีอยู่ในรากรวมที่มันส่งกิจกรรมไปให้ 'ตรรกะ' เพียงอย่างเดียวที่มีอยู่ใน Saga คือ 'กระบวนการ' - ตรรกะ (มักใช้เป็น Statemachine) ซึ่งพิจารณาจากการกระทำที่ได้รับ (เช่นเดียวกับเหตุการณ์ติดตาม) จะทำอย่างไร (เช่น: กิจกรรมที่จะส่ง)
  4. รูปแบบ Saga ใช้รูปแบบธุรกรรมแบบกระจาย Ie: เมื่อหนึ่งในรากรวม (ซึ่งทำงานได้อย่างอิสระอีกครั้งโดยไม่ทราบว่ามีอยู่จริง) ล้มเหลวการกระทำทั้งหมดอาจต้องย้อนกลับ
  5. สิ่งนี้ถูกนำไปใช้โดยมีรากรวมทั้งหมดเมื่อเสร็จสิ้นการรายงานกิจกรรมของพวกเขากลับไปที่ Saga (ในกรณีที่ประสบความสำเร็จเช่นเดียวกับข้อผิดพลาด)
  6. ในกรณีที่รากรวมทั้งหมดคืนความสำเร็จ Statemachine ภายในถ้า Saga พิจารณาว่าจะทำอย่างไรต่อไป (หรือตัดสินใจว่าจะทำเสร็จ)
  7. ในกรณีของความล้มเหลว Saga จะส่งต่อไปยังรากรวมทั้งหมดที่เข้ามามีส่วนร่วมในการกระทำครั้งสุดท้ายที่เรียกว่า Compensation Action เช่น: การกระทำเพื่อยกเลิกการกระทำสุดท้ายที่รากรวมได้
  8. นี่อาจเป็นเพียงการทำ 'ลบ 1 โหวต' หากการกระทำนั้นเป็น "บวก 1 คะแนน" แต่มันอาจซับซ้อนกว่าเช่นการกู้คืนโพสต์บล็อกในเวอร์ชันก่อนหน้า
  9. การจัดหากิจกรรม (ดูบล็อกของการรวมทั้งสอง) มีเป้าหมายที่จะทำให้การบันทึกผลลัพธ์ของแต่ละกิจกรรมที่แต่ละรากรวมรวมที่ดำเนินการกับศูนย์จัดเก็บเหตุการณ์ส่วนกลาง (การเปลี่ยนแปลงที่เรียกว่า 'เหตุการณ์' ในบริบทนี้)
  10. ที่จัดเก็บกิจกรรมนี้เป็น 'เวอร์ชั่นจริงของความจริง' และสามารถใช้เพื่อเล่นซ้ำสถานะของเอนทิตีทั้งหมดได้ง่ายๆโดยการวนซ้ำเหตุการณ์ที่เก็บไว้ (เป็นหลักเช่นบันทึกเหตุการณ์)
  11. การรวมสอง (เช่น: การปล่อยให้รูทรวมใช้การจัดหากิจกรรมเพื่อบันทึกการเปลี่ยนแปลงภายนอกก่อนที่จะรายงานกลับไปที่ Saga) ทำให้มีความเป็นไปได้ที่ดีซึ่งหนึ่งในนั้นเกี่ยวข้องกับคำถามของฉัน ...

ฉันรู้สึกว่าฉันต้องถอดสิ่งนี้ออกจากไหล่ของฉันเพราะมันเป็นเรื่องที่เข้าใจได้ในครั้งเดียว รับบริบท / ความคิดนี้ (อีกครั้งโปรดแก้ไขหากผิด)

คำถาม:เมื่อรูทรวมได้รับการชดเชยการกระทำและถ้ารูทการรวมนั้นมีการเอาต์ซอร์ซมันเป็นการเปลี่ยนแปลงสถานะโดยใช้การจัดหากิจกรรมการกระทำที่ชดเชยในทุกสถานการณ์จะไม่ถูกลบในเหตุการณ์สุดท้ายใน Event Store ได้รับ Root Root (สมมติว่าการใช้งานคงอยู่สามารถลบได้)

นั่นจะทำให้รู้สึกถึงฉันมาก (และจะเป็นประโยชน์อย่างมากจากการรวมกันนี้) แต่อย่างที่ฉันบอกว่าฉันอาจจะทำให้สมมติฐานเหล่านี้ขึ้นอยู่กับความเข้าใจที่ไม่ถูกต้อง / ไม่สมบูรณ์ของแนวคิดเหล่านี้

ฉันหวังว่านี่จะไม่ได้ยืดยาวเกินไป

ขอบคุณ

คำตอบ:


9

คุณไม่ควรลบกิจกรรมจากที่จัดเก็บกิจกรรมของคุณ สิ่งเหล่านี้แสดงถึงสิ่งที่เกิดขึ้น หากสิ่งที่เกิดขึ้นตอนนี้คุณควรจะรู้เช่นกันดังนั้นเพิ่มเหตุการณ์ที่จะบังคับให้มวลรวมของคุณกลับไปสู่สถานะเดิม น่าเสียดายที่ลบข้อมูลออกจากฐานข้อมูลของคุณ

คิดเกี่ยวกับตัวอย่างของเกวียนจากเกรกอยังและของที่ถูกลบออก อาจเป็นพรุ่งนี้ข้อมูลของการชดเชยการกระทำอาจมีค่าใด ๆ ..

สำหรับเทพนิยายทุกสิ่งถูกต้องเท่าที่ฉันรู้จักตัวเอง คุณควรนึกถึงเทพนิยายในฐานะกลไกรัฐ มันเท่านั้นที่

มันเป็นคำสั่งเทพนิยายที่ออกมาบอกให้มวลรวมทำอะไรบางอย่าง จากการกระทำนี้จะมีเหตุการณ์ เหตุการณ์นี้อาจเป็นการดำเนินการแก้ไขที่คุณต้องการหรืออาจจำเป็นต้องมีการลดความซ้ำซ้อนในมุมมองเพื่อให้ผู้ใช้บางคนเห็นการตัดสินใจว่าจะทำอย่างไร

ขึ้นอยู่กับกฎเกณฑ์ทางธุรกิจของคุณ อย่างใดอย่างหนึ่งมีการแก้ไขที่ง่าย: รากรวมรู้ว่าในกรณีดังกล่าวคุณทำเช่นนั้นหรือตัวเลือกมีความซับซ้อนเกินกว่าจะดำเนินการทางโปรแกรม (ต้นทุนการพัฒนาสูงเกินไป) และดังนั้นคุณอาจเสนอสิ่งนี้กับผู้ใช้บางคน อาจเลือกระหว่างการกระทำที่แตกต่างกัน ทุกอย่างขึ้นอยู่กับบริบทของการดำเนินการชดเชย นี่คือกฎทางธุรกิจที่บริสุทธิ์ เราควรทำอย่างไรในกรณีนี้หรือกรณีนั้น นี่คือสิ่งที่ถามผู้เชี่ยวชาญด้านโดเมนของคุณจากนั้นเลือกกับเขาถ้าเป็นการดีกว่าที่จะพัฒนาโซลูชันอัตโนมัติหรือถ้าวิธีแก้ปัญหาคือถามผู้ใช้ Ronald R. เพราะเขาเป็นผู้ตอบคำถามนี้โดยปกติ


มวลรวมจะทราบได้อย่างไรว่าจะเปลี่ยนกลับเป็นรัฐใด มันจะได้รับอนุญาตให้สอบถามกับร้านค้ากิจกรรมหรือบางสิ่งบางอย่าง?
Geert-Jan

ไม่ควรเปลี่ยนกลับ แต่เพิ่มกิจกรรมอื่น มันเป็นคำสั่งเทพนิยายที่ออกมาบอกให้มวลรวมทำอะไรบางอย่าง จากการกระทำนี้จะมีเหตุการณ์
Arthis

ใช่ฉันเข้าใจ. "เปลี่ยนกลับ" อาจไม่ถูกเลือก ลองพิจารณาสิ่งต่อไปนี้: ฉันอาจต้องการใช้การจัดหากิจกรรมกับ Sagas สำหรับการสร้างแบบจำลองเหนือสิ่งอื่นใดกระบวนการเผยแพร่เอกสาร / การอนุมัติ จะเกิดอะไรขึ้นถ้าบรรณาธิการส่ง ChangeBlogBody-action ซึ่งท้ายที่สุดคงเป็น BlogBodyChanged-event ไปยัง Event Store หลังจากนั้นด้วยเหตุผลบางอย่างจะมีการออกคำสั่งการชดเชย กลุ่มคนจะรู้ได้อย่างไรว่าจะชดเชยเหตุการณ์ที่จะเกิดขึ้นซึ่งส่งผลให้เนื้อหาของบล็อกเป็นเหมือนก่อนที่จะมีการออก ChangeBlogBody-action
Geert-Jan

ขึ้นอยู่กับกฎเกณฑ์ทางธุรกิจของคุณ อย่างใดอย่างหนึ่งมีการแก้ไขที่ง่าย: รากรวมรู้ว่าในกรณีดังกล่าวคุณทำเช่นนั้นหรือตัวเลือกมีความซับซ้อนเกินไปที่จะทำโดยทางโปรแกรม (ต้นทุนการพัฒนาสูงเกินไป) และดังนั้นคุณอาจเสนอให้ผู้ใช้บางคน อาจเลือกระหว่างการกระทำที่แตกต่างกัน
Arthis

ทุกอย่างขึ้นอยู่กับบริบทของการดำเนินการชดเชย นี่คือกฎทางธุรกิจที่บริสุทธิ์ เราควรทำอย่างไรในกรณีนี้หรือกรณีนั้น นี่คือสิ่งที่ถามผู้เชี่ยวชาญด้านโดเมนของคุณจากนั้นเลือกกับเขาถ้าเป็นการดีกว่าที่จะพัฒนาโซลูชันอัตโนมัติหรือถ้าวิธีแก้ปัญหาคือถามผู้ใช้ Ronald R. เพราะเขาเป็นผู้ตอบคำถามนี้โดยปกติ
Arthis

6

เพื่อความสมบูรณ์ฉันคิดว่าจะรวมข้อมูลที่เกี่ยวข้องจาก Martin Fowler เกี่ยวกับวิธีเปลี่ยนสถานะ:

เช่นเดียวกับเหตุการณ์ที่เล่นตัวเองส่งต่อก็มักจะมีประโยชน์สำหรับพวกเขาที่จะสามารถย้อนกลับตัวเอง

การกลับรายการเป็นสิ่งที่ตรงไปตรงมาที่สุดเมื่อเหตุการณ์ถูกส่งในรูปแบบของความแตกต่าง ตัวอย่างนี้จะเป็น "เพิ่ม $ 10 ไปยังบัญชีของ Martin" ซึ่งตรงข้ามกับ "ตั้งค่าบัญชีของ Martin เป็น $ 110" ในกรณีก่อนหน้านี้ฉันสามารถย้อนกลับได้ด้วยการลบ $ 10 แต่ในกรณีหลังฉันไม่มีข้อมูลเพียงพอที่จะสร้างมูลค่าที่ผ่านมาของบัญชีอีกครั้ง

หากเหตุการณ์อินพุตไม่เป็นไปตามแนวทางที่แตกต่างกันเหตุการณ์นั้นควรทำให้แน่ใจว่ามันเก็บทุกอย่างที่จำเป็นสำหรับการกลับรายการในระหว่างการประมวลผล คุณสามารถทำได้โดยการจัดเก็บค่าก่อนหน้าในค่าใด ๆ ที่มีการเปลี่ยนแปลงหรือโดยการคำนวณและจัดเก็บความแตกต่างในเหตุการณ์

จาก: http://martinfowler.com/eaaDev/EventSourcing.html


1

แนวคิด:

  • เหตุการณ์คือสิ่งที่เกิดขึ้น อดีตไม่สามารถเปลี่ยนแปลงได้
  • คำสั่งเป็นสิ่งที่ต้องทำ คำสั่งอาจไม่เกิดขึ้น (อาจถูกปฏิเสธ)

เราสามารถเปลี่ยนสถานะในอนาคตของเราได้โดยการดำเนินการคำสั่งอื่น (ชดเชยการกระทำ) ซึ่งจะส่งผลให้เหตุการณ์การเปลี่ยนแปลงสถานะของแอพลิเคชัน

หากต้องการ "ขจัดความสับสน" คำถามให้คิดเกี่ยวกับวลีนี้ "ลบกิจกรรมสุดท้าย":

  • ถ้าเหตุการณ์สุดท้ายไม่ใช่เหตุการณ์ที่ต้องลบ จะเกิดอะไรขึ้นถ้ามีเหตุการณ์อื่นเกิดขึ้นหลังจากเหตุการณ์ที่ถูกลบ กิจกรรมเหล่านี้จะต้องเปลี่ยนด้วย (เนื่องจากสถานะพื้นฐานของพวกเขาจะมีการเปลี่ยนแปลงโดยการลบกิจกรรมก่อนหน้าพวกเขา)
  • ถ้าเหตุการณ์ถูกส่งไปยังระบบภายนอก คุณอาจไม่สามารถแก้ไขสถานะอื่นนอกจากส่งเหตุการณ์อื่น

ในระยะสั้นคุณไม่มีตัวเลือกในการลบกิจกรรมภายในรูปแบบ CQRS

คุณอาจย่อขนาดร้านค้ากิจกรรมของคุณโดยกำหนดสถานะสแนปชอต (ซึ่งขึ้นอยู่กับกิจกรรมทั้งหมดที่นำไปสู่สถานะนั้น) แต่ลักษณะทางกายภาพนี้ไม่มีส่วนเกี่ยวข้องกับแนวคิดของเหตุการณ์


0

Geert-Jan ฉันคิดว่าการดำเนินการชดเชยสามารถลบเหตุการณ์ที่เกี่ยวข้องได้ มันสมเหตุสมผลและแสดงให้เห็นประโยชน์อีกประการหนึ่งของรูปแบบการออกแบบการจัดหาเหตุการณ์: การนำรูปแบบการออกแบบการทำธุรกรรมไปใช้งานได้ง่ายขึ้น

บางคนบอกว่าการลบกิจกรรมละเมิด "หลักการ" ของการจัดหากิจกรรมหรือ CQRS ฉันคิดว่านั่นเป็นข้อ จำกัด ทั่วไป ฉันคิดว่ามันโอเคที่จะลบกิจกรรมถ้ามันถูกสร้างขึ้นภายในขอบเขตของธุรกรรมทั่วโลกที่จะถูกยกเลิก พิจารณารหัสเทียม:

try {
    newEvents = processMycommand(myCommand)
    for (Event newEvent : newEvents)
        EventStore.insertEvent(newEvent);
} catch (Exception e) {
    EventStore.rollback();
}

สมมติว่าที่เก็บเหตุการณ์ของคุณเป็นฐานข้อมูลธุรกรรม ในรหัสเทียมคุณสามารถจินตนาการถึงสถานการณ์ที่คุณแทรกเหตุการณ์แรก แต่เมื่อพยายามแทรกเหตุการณ์ที่สองที่มีการยกเว้นเกิดขึ้น คำสั่ง rollback จะเปลี่ยนการแทรกของเหตุการณ์แรกตามธรรมชาติ นั่นสมเหตุสมผลหรือไม่

หากมันสมเหตุสมผลสำหรับธุรกรรมฐานข้อมูล ACID (ธุรกรรมที่มีการกระทำ / ย้อนกลับ) ทำไมมันไม่สมเหตุสมผลสำหรับการทำธุรกรรมชดเชย

เมื่อดำเนินธุรกรรม Global Saga การเปลี่ยนแปลงข้อมูลสามารถยกเลิกได้ (โดยการชดเชย) ไม่จำเป็นต้องเก็บเหตุการณ์ที่สร้างขึ้นระหว่างการทำธุรกรรมเพราะการทำธุรกรรมไม่เสร็จสมบูรณ์

ทีนี้ถ้าการชดเชยพยายามลบเหตุการณ์และเหตุการณ์นั้นไม่ใช่เหตุการณ์ล่าสุดบนวัตถุการลบจะไม่เกิดขึ้น แต่โดยทั่วไปนั่นไม่น่าจะเกิดขึ้นโดยเฉพาะในโซลูชันที่ต้องอ่านมาก


0

ลองเล่นด้วยความคิดที่ว่าพื้นที่จัดเก็บข้อมูลเป็นเพียงข้อมูลที่คุณต้องการบันทึก ตัวอย่างเช่นเราสามารถมีฮาร์ดไดรฟ์เราสามารถเริ่มต้นและเขียนข้อมูลได้ ทุกครั้งที่เรามีเหตุการณ์ที่เราผนวกข้อมูลก่อนหน้าของเราดังนั้นเราเพิ่งเขียนบนดิสก์ที่เราหยุดครั้งล่าสุด เมื่อเราต้องการลบกิจกรรมที่เราย้อนกลับไปให้ลบส่วนนั้นออกจากดิสก์แล้วปล่อยให้มีช่องว่าง การย้ายกลับด้วยตัวของมันเองทำให้การจัดเก็บเหตุการณ์ของเราช้าลง แต่เราสามารถอยู่กับมันได้ หากเราใช้ระบบไฟล์ที่จะพยายามเติมเต็มช่องว่างด้วยเหตุการณ์ที่เกิดขึ้นในภายหลังดังนั้นเราจะพบว่ามีการแยกส่วนของหน่วยความจำช้าหรือเราสามารถทำการจัดเรียงข้อมูลได้ ทั้งสองอย่างนั้นเป็นสิ่งที่เราชอบ หากเรากำลังพูดถึงฐานข้อมูลคุณจะได้รับสิ่งนี้หากคุณใช้ฐานข้อมูลเชิงสัมพันธ์แทนการผนวกเฉพาะฐานข้อมูลสำหรับจัดเก็บกิจกรรมของคุณ:

ป้อนคำอธิบายรูปภาพที่นี่ อ้างอิง: https://cambridge-intelligence.com/bringing-time-series-data-to-life-with-keylines/

Ofc โดยไซต์ปกติสิ่งนี้ไม่สำคัญ แต่โซลูชันเหล่านี้ได้รับการออกแบบมาสำหรับเว็บไซต์ขนาดใหญ่เช่น facebook, google, etc ... ดังนั้นจริงๆคำถามไม่สมเหตุสมผลเพราะคุณจะลบเหตุการณ์ในฐานข้อมูลผนวกเท่านั้นและวิธีการที่จะ คุณโทรหาสิ่งชดเชยเช่นสร้างเครื่องย้อนเวลาและย้อนเวลากลับไปเพื่อเปลี่ยนแปลงหรือป้องกันเหตุการณ์

AFAIK. วิธีเดียวในการแก้ไขปัญหานี้คือการสร้างที่เก็บข้อมูลเหตุการณ์ใหม่ที่คุณยกเว้นกิจกรรมที่คุณไม่ต้องการและหลังจากนั้นให้ลบที่เก็บกิจกรรมเก่าออก แต่นี่เป็นทางออกที่ยอดเยี่ยมในการลบเหตุการณ์เดียว หากเรากำลังพูดถึง GDPR อยู่แล้วทางออกที่ดีที่ฉันรู้จักคือเก็บข้อมูลส่วนบุคคลที่เข้ารหัสไว้ในที่จัดเก็บเหตุการณ์และลบคีย์การเข้ารหัสออกจากฐานข้อมูลอื่น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.