ADR-0002. Eventing chỉ-WebSocket in-process, không Kafka
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-05-01 |
| Deciders | outreach-team |
| Supersedes | — |
Bối cảnh
- Phần lớn service BANA emit Kafka event cho CDC và choreography cross-service.
- Outreach thu thập yêu cầu và subscription từ site công khai. Consumer downstream duy nhất là BO dashboard, vốn muốn một toast real-time khi có yêu cầu mới.
- Không service nào khác cần phản ứng với một yêu cầu hay subscription như một domain event. Bản ghi bền là dòng trong PostgreSQL.
Quyết định
Outreach ship không Kafka producer và không Kafka consumer, và không BullMQ worker. Bề mặt async duy nhất của nó là một WebSocketEmitter backed bởi Redis (outreach-ws-emitter) broadcast INQUIRY_SUBMITTED tới room quan sát khi một yêu cầu được submit.
Emission là fire-and-forget: yêu cầu được commit vào database trước, rồi OutreachSocketEventService.notifyInquirySubmitted() chạy mà không await, guard bởi isReady() và dùng Promise.allSettled qua các room. Một WS event bị rớt không bao giờ mất dữ liệu — BO có thể re-fetch qua GET /inquiries.
Hệ quả
| Ưu | Nhược |
|---|---|
| Hạ tầng tối thiểu: không Kafka topic, schema, consumer group, hay DLQ phải vận hành | Nếu một service tương lai cần inquiry event, nó phải poll REST hoặc phải thêm một seam Kafka |
| UX BO real-time qua Redis fan-out (hoạt động qua các replica) | Delivery WS là best-effort, không bền |
| Service đơn giản hơn: ít failure mode, blast radius nhỏ hơn | Không nhất quán với chuẩn Kafka-CDC ở nơi khác trong nền tảng |
| Database vẫn là nguồn chân lý duy nhất | Analytics trên yêu cầu phải đọc DB, không phải một event stream |
Các phương án đã cân nhắc
| Phương án | Ưu | Nhược | Lý do loại bỏ |
|---|---|---|---|
Emit Kafka inquiry.submitted | Bền, fan-out tới bất kỳ consumer nào, hợp chuẩn nền tảng | Trọng lượng vận hành (topic, consumer, DLQ) cho một consumer nội bộ | Không có consumer bền nào hôm nay |
Debezium CDC trên bảng Inquiry | Zero app code; bắt mọi ghi | Hạ tầng nặng cho một bảng traffic thấp; ghép consumer với schema | Không tương xứng với nhu cầu |
| Await WS notify trong request | Đảm bảo notify trước 201 | Ghép latency/availability submit với Redis health | Submit phải thành công ngay cả khi Redis down |
Tham chiếu
packages/outreach/src/components/websocket/component.ts(ApplicationWebSocketComponent)packages/outreach/src/components/websocket/socket-event.service.ts(notifyInquirySubmitted)packages/outreach/src/application.ts(không config component Kafka/BullMQ)- API Events