Communication — Khái niệm cốt lõi
Các artifact (vật thể) và "grain"
"Grain" = mức độ chi tiết của một bản ghi (một bản ghi đại diện cho cái gì).
| Artifact | Kho | Grain | Vai trò |
|---|---|---|---|
| NotificationJob | Azure Table | 1 sự kiện thông báo | Đầu vào: "có việc cần gửi". |
| NotificationScheduler | SQL | 1 việc chờ xử lý | Hàng đợi báo Scheduler đến lấy việc. |
| MessagingJob + Blob | SQL + Blob | 1 payload lớn | Điều phối campaign/report (nội dung lớn để ở Blob). |
| UserMessage | Azure Table | 1 người nhận | Tin in-app; hộp thư trong app. |
| OutgoingMessage | Azure Table | 1 người nhận × 1 kênh | Tin gửi ra qua provider; mang trạng thái gửi. |
Pipeline gửi: ba bước
| Bước | Làm gì |
|---|---|
| Scheduler | Quét việc Ready; đánh giá Notification Settings (loại này có bật, gửi cho ai). |
| Generator | Render template + resolve người nhận; sinh UserMessage (in-app) và/hoặc OutgoingMessage (kênh ngoài). |
| Distributor | Gửi thật qua SendGrid/Twilio; "claim trước khi gửi". |
| Webhook & Tracker | Cập nhật trạng thái (delivered/bounce/opened) về OutgoingMessage. |
Bốn nguyên tắc xương sống
Mọi quyết định trong Communication suy ra từ 4 nguyên tắc (chia sẻ với nền automation):
Khóa định danh thay vì khóa ngẫu nhiên — mỗi sự việc có đúng một khóa tất định; mọi khóa hạ nguồn (OutgoingMessage…) đều dẫn xuất từ đó. Event lặp/retry sinh cùng khóa → không trùng.
Ensure*thay vìCreate*— mọi thao tác tạo artifact là "đảm bảo tồn tại": đã có và tương thích → thành công luôn (idempotent); đã có nhưng lệch nội dung (InputHashkhác) → xung đột, dừng gửi tự động, báo support. Không bao giờUpsert Replaceđể khỏi vô tình gửi lại.Claim trước khi gửi — Distributor phải chuyển
OutgoingMessagesangSendingbằng một cập nhật có điều kiện trước khi gọi provider. Tin trùng trong queue thấy dòng đãSending/Sentthì thoát — người dùng không nhận email đúp.Reconciliation có biên thay vì outbox — không xây outbox phức tạp; 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á sự cố hiếm.
⚠️ Ngoại lệ của nguyên tắc no-replace:
EntityHistory(audit) được phép upsert InsertOrReplace theo khóa tất định, vìRowKeycủa nó không bị tham chiếu từ ngoài và ghi đè khi retry là vô hại.NotificationJobthì giữ query-before-append.
Template
Nội dung tin là template có placeholder {{...}} (ví dụ {{INCIDENT_DETAILS_LINK}}). Generator điền dữ liệu thật lúc render. Template có key + version (nằm trong nhóm "immutable routing fields" — không đổi giữa chừng một lần gửi).
Trường immutable vs mutable
Khi Ensure* so khớp một artifact đã tồn tại, nó phân biệt:
- Immutable (định danh tin): source coordinates, event type, recipient identity, delivery method, template key/version, run key, automation coordinates. Lệch → xung đột, dừng gửi.
- Mutable (có thể đổi an toàn): retry counters, scheduler coordinates, provider status, webhook timestamps, diagnostics có giới hạn.
Hiểu rồi? Xem cách chúng ráp thành hệ thống ở Kiến trúc.