Skip to content

ADR-0002. Activity notification nạp từ Kafka, lưu trong core, rồi đẩy đi

TrườngGiá trị
StatusAccepted
Date2026-05-20
DecidersPhat Nguyen
Supersedes-

Bối cảnh

  • Sự kiện domain (ví dụ thanh toán thành công) cần trở thành notification bền vững, theo từng user, hiển thị trong UI "chuông" kèm một tín hiệu báo trực tiếp qua WS.
  • Producer biết điều gì đã xảy ra và một phạm vi người nhận (org / merchant / danh sách users cụ thể) nhưng không biết danh sách người nhận thực tế.
  • Signal đã sở hữu điểm biên WebSocket nhưng không có schema; bảng ActivityNotification được tập trung trong @nx/core.
  • Notification phải tồn tại được kể cả khi socket bị lỡ - client có thể đang offline lúc sự kiện phát sinh.

Quyết định

Chúng ta sẽ nạp activity notification vào Signal qua Kafka (signal.activity-notification), và để worker phân giải → lưu → đẩy đi:

  1. Tiêu thụ TActivityNotificationMessage; từ chối eventType lạ.
  2. Phân giải người nhận ở phía server - org/merchant qua PolicyDefinitionRepository, users qua recipientIds cụ thể (mặc định lui về [actorId]).
  3. Dựng content + html từ một markdown decorator, lưu một hàng ActivityNotification cho mỗi người nhận qua createAll.
  4. Đẩy observation/signal/notification/created tới từng room signal/notification/{recipientId}.

Consumer chạy với autocommit: false, commit theo từng message sau khi handler trả về, và fallbackMode: latest.

Hệ quả

ƯuNhược
Notification vừa bền vững (DB) vừa trực tiếp (WS)Gửi lại sẽ tạo hàng trùng - hiện chưa khử trùng lặp
Producer chỉ cần lo phạm vi; Signal đảm nhận việc phân giải người nhậnPhân giải người nhận là một lần truy vấn DB đồng bộ cho mỗi message
Tái dùng schema/repo tập trung của @nx/coreLỗi handler chỉ được ghi log chứ không retry/DLQ
Commit thủ công đảm bảo an toàn ở mức ít nhất một lầnHiện mới chỉ hiện thực nội dung cho PAYMENT_SUCCESS

Phương án đã cân nhắc

Phương ánƯuNhượcVì sao loại
Chỉ đẩy qua WS (không lưu)Đơn giản nhấtMất nếu client offline; không có lịch sửUI chuông cần lịch sử bền vững
Producer tự phân giải người nhận + ghi hàngSignal giữ đơn giảnMỗi producer lặp lại việc phân giải + phải biết schemaTập trung trong Signal đỡ trùng lặp hơn
Autocommit + idempotency keyÍt code thủ côngCần kho lưu khử trùng lặp; chưa xâyTạm hoãn; commit thủ công là phương án an toàn trung gian

Tham chiếu

  • signal/src/components/notification/component.ts (cấu hình consumer)
  • signal/src/services/activity-notification-worker.service.ts (phân giải/lưu/đẩy)
  • core/src/common/kafka/types.ts (TActivityNotificationMessage)
  • API Events - idempotency

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.