ADR-0002. Triển khai theo Mode (FULL / API / WORKER)
| Trường | Giá trị |
|---|---|
| Trạng thái | Accepted |
| Ngày | 2026-02-05 |
| Người quyết định | payment-team, SRE |
| Thay thế | — |
Bối cảnh
- Service payment xử lý hai khối lượng công việc khác nhau:
- Tiếp nhận REST + IPN — đồng bộ, nhạy cảm về độ trễ, scale theo lưu lượng nhà cung cấp.
- BullMQ worker — bất đồng bộ (scheduler + confirmation), scale theo độ sâu queue.
- Chạy cả hai trong một process hạn chế khả năng scale độc lập và khuếch đại bán kính sự cố crash.
- Tuy nhiên, môi trường dev cần mọi thứ trong một pod.
Quyết định
Một image, ba mode triển khai chọn qua APP_ENV_MQ_PAY_MODE:
| Mode | Controllers | Queue producer | Workers | Trường hợp sử dụng |
|---|---|---|---|---|
FULL (mặc định) | ✓ | ✓ | ✓ | Dev — single pod |
API | ✓ | ✓ | ✗ | Tier REST production — scale theo tốc độ request |
WORKER | ✗ | ✗ | ✓ | Tier worker production — scale theo độ sâu queue |
Mẫu production: 1× API + N× WORKER. Mỗi pod WORKER phải có APP_ENV_NODE_ID duy nhất (Snowflake worker ID = 91, 92, …).
Hệ quả
| Ưu điểm | Nhược điểm |
|---|---|
| REST và worker scale độc lập | Ba manifest triển khai cần duy trì |
| Worker crash không làm sập API | Yêu cầu khóa mã hóa chia sẻ (APP_ENV_APPLICATION_SECRET) |
| Dev vẫn dùng single pod (FULL) | Pod WORKER cần snowflake ID duy nhất — dễ sai sót |
| Topology chuẩn "API + worker" | Mode mismatch có thể gây dead queue âm thầm |
Phương án thay thế đã cân nhắc
| Lựa chọn | Ưu điểm | Nhược điểm | Lý do từ chối |
|---|---|---|---|
| Một mode duy nhất (luôn full) | Vận hành đơn giản hơn | Không thể scale REST và worker độc lập | Sai tradeoff cho production |
| Tách image API và WORKER | Ranh giới rõ ràng | Phức tạp build pipeline; rủi ro image drift | Single-image-multi-mode là tiêu chuẩn ngành |
| Worker stateless không có BullMQ | Không phụ thuộc Redis | Không có retry / scheduler / persistence | mq-pay cần ngữ nghĩa queue |
Tham chiếu
@nx/mq-pay/src/common/constants.ts:11-14(MQPayRunModes)@nx/mq-pay/src/component.ts:437-444(xác minh mode)src/components/payment.component.ts:124-125(giải quyết mode)