ข้ามไปยังเนื้อหา

เหตุการณ์โดเมน

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

DomainEventBus เป็นบัสเผยแพร่/สมัครรับแบบกระจายสัญญาณภายในโปรเซส ผู้เผยแพร่ เรียก publish(event) ส่วนผู้สมัครรับบริโภคสตรีม on<T>() ที่มีชนิดกำกับ ทุกเหตุการณ์อิมพลีเมนต์ DomainEvent และพก occurredAt มาด้วย

บัสทำงานอยู่ภายใน cc_server ผู้เผยแพร่ทุกตัวและผู้สมัครรับที่มีชีวิตทุกตัว อยู่ที่นั่น ไม่มีไคลเอนต์ใดเห็นบัสนี้ สิ่งที่ไคลเอนต์เห็นคือชุดย่อยที่คัดสรรมาแล้ว ซึ่งเซิร์ฟเวอร์ส่งซ้ำออกมาเป็นเฟรม JSON-RPC notifications/*

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

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

ต้นทุนที่ต้องจ่ายก็คือแบบที่คุ้นเคย: ผู้เผยแพร่บอกไม่ได้ว่ามีใครฟังอยู่หรือไม่ และผู้ฟังที่ไม่เคยถูกสร้างขึ้นมาก็เงียบงันอยู่เฉยๆ โดยไม่มีใครรู้ TicketRemoteSyncHandler คือตัวอย่างที่ยืนยง: มันถูกประกาศไว้ มีเทสต์ครอบคลุม แต่ไม่เคยถูกต่อเข้าใน โปรดักชัน

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

ร่องรอยการตรวจสอบไม่ใช่ภาพฉายของสตรีมเหตุการณ์ ทุกการดำเนินการ RPC ที่เปลี่ยนแปลงข้อมูลจะถูกตรวจสอบเป็นค่าเริ่มต้น — RepoOp.audited มีค่าเริ่มต้น เป็น true และการดำเนินการจะเลือกไม่ถูกตรวจสอบก็ต่อเมื่อประกาศ audited: false ซึ่งเป็นการกระทำที่จงใจและมองเห็นได้บนตัวการดำเนินการนั้นเอง ตัวดิสนพัตเชอร์ ผนวกรายการ “ใครทำอะไร จากที่ไหน” เข้าไปโดยตรงหลังการเรียกที่สำเร็จ ไม่มี DomainEventAuditBridge ActivityLogPersister เขียนแถว activity_log จาก เหตุการณ์ ActivityLogged ซึ่งเป็นฟีดแยกต่างหากจากการตรวจสอบ RPC

บัสเหตุการณ์ คือ ช่องทางขนส่งสำหรับการแจ้งเตือนและสำหรับระบบอัตโนมัติ แต่ไม่ใช่ระบบบันทึกหลัก

  • การแจ้งเตือน คลาสเหตุการณ์ยี่สิบเอ็ดคลาสถูกเซิร์ฟเวอร์เปลี่ยนเป็นเฟรมบนสาย notifications/* บันทึกลงฟีดแบบคงทนต่อเวิร์กสเปซ และกระจายไปยังเซสชันที่เชื่อมต่อ อยู่ เฟรมใดที่มี workspace_id ชี้ไปยังเวิร์กสเปซที่ผู้ใช้ของเซสชันไม่ได้เป็น สมาชิกจะถูกทิ้งที่เซิร์ฟเวอร์ จากนั้นไคลเอนต์จึงกรองส่วนที่เหลือให้เหลือเฉพาะ เวิร์กสเปซที่กำลังดูอยู่
  • ระบบอัตโนมัติที่ขับเคลื่อนด้วยเหตุการณ์ ทริกเกอร์ไปป์ไลน์สมัครรับจากบัส และเริ่มไปป์ไลน์ที่ตรงกันโดยอัตโนมัติ (ดูด้านล่าง)
  • ปฏิกิริยาตามวงจรชีวิต การสร้างเวิร์กสเปซจะตั้งต้นเอเจนต์ CEO และเอเจนต์ ผู้เชี่ยวชาญ เทมเพลตไปป์ไลน์ที่มีมาให้ในตัว และชุดการประเมินเริ่มต้น การรัน เอเจนต์ที่เสร็จสมบูรณ์จะทำขั้นตอนไปป์ไลน์ที่ถูกระงับไว้ให้ดำเนินต่อ ปิดงาน ป้อนข้อมูลให้ผู้ดูแลเป้าหมาย ปลุกตัวตรวจที่ระบุชื่อไว้ได้ และทริกเกอร์หัวหน้าทีม ซ้ำได้ PR ที่ถูกรวมหรือสเปซที่ถูกลบจะทริกเกอร์การเก็บกวาด worktree
  • การซิงค์ข้ามผู้ให้บริการ การเปลี่ยนแปลงตั๋วงานภายในเครื่องถูกส่งออกไปยัง ผู้ให้บริการที่กำหนดค่าไว้ โดยตัวประสานงานที่ฟังเหตุการณ์ตั๋วงานห้าเหตุการณ์

เหตุการณ์ครอบคลุมพื้นผิวทั้งผลิตภัณฑ์ ในภาพรวม:

  • เวิร์กสเปซ เอเจนต์ และรีโป — การสร้างเวิร์กสเปซ การรันเสร็จสมบูรณ์ การลงทะเบียนรีโป การอัปเดตสกิล
  • Pull request — การเผยแพร่ การเปลี่ยนสถานะ การรวม คำขอรีวิว การถูกกล่าวถึง การเฝ้าดู PR ที่คุณเปิดไว้ และ PR ที่ตรวจพบจากภายนอก
  • การรับส่งข้อความ — ข้อความ สเปซ และความคืบหน้าการจัดเตรียมสเปซ
  • ตั๋วงาน — สร้าง มอบหมาย มอบหมายใหม่ รายละเอียด สถานะ และผลลัพธ์ขั้นสุดท้ายทั้งสามอย่าง
  • งาน — เฟรมวงจรชีวิตที่เรียงลำดับไว้สำหรับการรันที่ถูกสั่งงานหนึ่งครั้ง ไคลเอนต์จึงเรียงลำดับและตัดรายการซ้ำได้
  • ไปป์ไลน์ — เฉพาะเหตุการณ์การรันขั้นสุดท้าย (เสร็จสมบูรณ์ ถูกยกเลิก ล้มเหลว)
  • การสังเกตการณ์ — รายการบันทึกกิจกรรมและเกณฑ์งบประมาณ
  • ตัวตนและสมาชิกภาพ — เพิ่มสมาชิก ลบสมาชิก เปลี่ยนบทบาท
  • ปฏิทินและการประชุม — การหมดอายุของการยืนยันตัวตน การเริ่มการประชุม และการบันทึกที่สิ้นสุด
  • ริก — การเข้าควบคุม การยึดคืน และการปิดโดยไม่คาดคิด

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

สำหรับแค็ตตาล็อกฉบับสมบูรณ์ — คลาสเหตุการณ์ที่เป็นรูปธรรมทั้ง 53 คลาส เพย์โหลด ของแต่ละคลาส และผู้สมัครรับ 24 รายที่บริโภคเหตุการณ์เหล่านี้ — ดูที่ ข้อมูลอ้างอิงเหตุการณ์โดเมน หน้านั้นคือ บัญชีรายการ ส่วนหน้านี้คือโมเดล

การควบคุมการเข้าถึงแบบสดใช้กลไกสองอย่างที่ต่างกัน

หัวข้อที่มีชื่อว่า “การควบคุมการเข้าถึงแบบสดใช้กลไกสองอย่างที่ต่างกัน”

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

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

การลบสมาชิกไม่ได้ปิดซ็อกเก็ต WorkspaceMemberRemoved ถูกบริโภค: LocalRpcServer และ RemoteRelayHost ทิ้งการสมัครรับเวิร์กสเปซที่ผู้ใช้รายนั้น ผูกไว้ และ RemoteEventForwarder ทำให้แคชสมาชิกภาพของตนเป็นโมฆะ เฟรมต่อๆ ไป สำหรับเวิร์กสเปซนั้นจึงไม่ถูกส่งออกไป สิ่งที่ปฏิเสธ RPC ถัดไปยังคงเป็นด่านตรวจ บทบาท ซึ่งแก้สมาชิกภาพใหม่ในทุกการเรียก — คำขอถัดไปของพวกเขาจึงถูกปฏิเสธ ด้วยข้อความ “Not a member of this workspace” ผลลัพธ์เกิดขึ้นทันทีกับทุกอย่าง ที่พวกเขาพยายามทำ เพียงแต่ไม่ได้เกิดจากการตัดสายทิ้ง

ทริกเกอร์ไปป์ไลน์สมัครรับเหตุการณ์โดเมนและเริ่มไปป์ไลน์ที่ตรงกันโดยอัตโนมัติ PipelineTriggerDispatcher ฟังทั้งบัส แล้ว:

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

ข้อจำกัดสำคัญคือข้อ 1 บัสพกชนิดเหตุการณ์ 53 ชนิด ตัวเลือกการเพิ่มทริกเกอร์ เริ่มการรันสำหรับสิบสี่ชนิดนี้ (สาขาเพย์โหลดของ EventPayloadMapper): ExternalPrDetected, PullRequestPublished, PullRequestStatusChanged, PrMerged, MessageReceived, TicketAssigned, TicketCompleted, TicketFailed, TicketCancelled, BudgetThresholdCrossed, RepoAdded, MeetingRecordingStopped, SkillUpdated และ SpaceDeleted ไม่มีชนิดอื่นที่เริ่มไปป์ไลน์ได้

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

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