Quy ước & nguyên tắc
Các nguyên tắc xương sống lặp lại ở mọi domain. Nắm chúng một lần, áp dụng khắp nơi.
Nguyên tắc kỹ thuật xương sống
1. Khóa định danh thay vì khóa ngẫu nhiên
Mỗi lần nghiệp vụ xảy ra có đúng một khóa tất định (suy từ danh tính sự kiện). Event lặp, retry, reconciliation đều cho cùng khóa → không bao giờ tạo hai bản ghi cho một lần nghiệp vụ. Mọi khóa hạ nguồn (NotificationJob, OutgoingMessage, EntityHistory…) đều dẫn xuất từ đó.
Ngoại lệ có chủ đích: flow action-derived (recipient/nội dung tính tại call-time, không có danh tính replay) cố ý dùng GUID ngẫu nhiên = at-least-once.
2. Ensure* thay vì Create*
Tạo artifact = "đảm bảo tồn tại": đã có + tương thích → success luôn (idempotent); đã có nhưng lệch nội dung → xung đột, dừng gửi tự động, báo support. Không Upsert Replace artifact gửi được (tránh gửi lại).
Ngoại lệ:
EntityHistoryđược InsertOrReplace theo khóa tất định (RowKey không bị tham chiếu ngoài, ghi đè vô hại).
3. Claim trước khi gửi
Trước khi gọi provider, chuyển OutgoingMessage sang Sending bằng cập nhật có điều kiện. Tin trùng thấy dòng đã Sending/Sent thì thoát → người dùng không nhận đôi.
4. Reconciliation có biên thay vì outbox
Không xây outbox phức tạp. Chấp nhận hiếm khi lỡ một sự kiện nguồn; mỗi provider tự khai một đường quét-sửa có giới hạn (watermark, cửa sổ ngày, batch) chạy tần suất thấp để vá.
5. Side effect độc lập, registry chỉ-thêm
Mỗi concern (notification, history…) là một post-processor độc lập duyệt registry riêng. Một concern lỗi không bỏ qua concern khác. Thêm concern mới = thêm post-processor mới, không phình routing handler hay rẽ nhánh trong post-processor có sẵn.
Các bảng invariant trong wiki là bản tóm tắt diễn giải để hiểu hành vi, không phải đặc tả đầy đủ. Khi nghi ngờ chi tiết → đối chiếu hành vi thật của hệ thống.
Quay lại Tổng quan Nền tảng hoặc khám phá các domain từ trang chủ.