Bỏ qua

ADR-0006: Dùng song song Kafka (event streaming) và BullMQ (job queue)

  • Status: Accepted
  • Date: ~2026-06-27 (backfilled 2026-07-25)
  • Supersedes: —
  • Superseded by: —

Bối cảnh

Kiến trúc microservices (ADR-0001) cần giao tiếp async cho 2 nhu cầu khác nhau:

  1. Phát sự kiện domain (booking created, payment completed...) để nhiều service khác nhau cùng lắng nghe, có thể replay/scale consumer độc lập.
  2. Xử lý job nội bộ có độ trễ/cần retry (gửi email, xử lý tác vụ nền) mà không cần nhiều consumer group khác nhau lắng nghe.

Dùng 1 công nghệ duy nhất cho cả 2 nhu cầu sẽ ép buộc trade-off không cần thiết (Kafka không có sẵn concept "job with delay/backoff" tiện lợi như BullMQ; BullMQ không phù hợp làm event bus cho nhiều consumer group độc lập theo kiểu pub/sub bền vững).

Quyết định

Tách rõ 2 công cụ theo đúng use case, đóng gói trong libs/messaging:

  • Kafka (libs/messaging/src/kafka, qua kafkajs): event streaming xuyên service — topic định nghĩa tại libs/shared/src/constants/kafka-topics.ts, dùng KafkaProducerService + @KafkaConsumer decorator
  • BullMQ (libs/messaging/src/bullmq, qua Redis): job queue nội bộ một service (retry, delay, backoff), qua QueueService
  • Cả hai đều có OpenTelemetry instrumentation riêng (@opentelemetry/instrumentation-kafkajs) để giữ tracing nhất quán (ADR-0004)

Lựa chọn khác đã cân nhắc

  • Chỉ dùng Kafka cho cả job queue: phải tự xây retry/backoff/delay logic trên Kafka (không có sẵn), phức tạp hơn nhiều so với dùng BullMQ có sẵn — loại.
  • Chỉ dùng BullMQ/Redis cho cả event streaming: mất khả năng replay event, không có consumer group độc lập bền theo kiểu Kafka, Redis không phải thiết kế cho durable log — loại.
  • RabbitMQ thay cho cả hai: có thể làm cả pub/sub và job queue, nhưng đổi cả 2 công nghệ đã chọn để hợp nhất về 1 broker duy nhất không cần thiết ở quy mô hiện tại — không xét lại vì thiếu động lực thay đổi.

Hệ quả

  • Được: mỗi công nghệ dùng đúng sở trường (Kafka: durable event log, nhiều consumer; BullMQ: retry/backoff/delay linh hoạt cho job nội bộ).
  • Đánh đổi: vận hành 2 hệ thống message riêng (Kafka cluster + Redis cho BullMQ) thay vì 1; dev cần biết khi nào dùng cái nào — cần convention rõ trong libs/messaging để tránh dùng nhầm.

Liên kết

  • Docs liên quan: docs/ARCHITECTURE.md (mục Communication — Async planned)
  • ADR liên quan: ADR-0001