ADR-0001: Dùng Go (thay vì mở rộng NestJS) cho 4 workload performance-critical
- Status: Accepted
- Date: ~2026-06-27 (backfilled 2026-07-25)
- Supersedes: —
- Superseded by: —
Bối cảnh
4 nhu cầu phát sinh không phù hợp với NestJS/Node.js single-threaded event loop:
| Vấn đề | Vì sao NestJS không phù hợp |
|---|---|
| PDF/QR generation tốn CPU | Block event loop, ảnh hưởng toàn bộ request khác trong cùng process |
| 10.000+ WebSocket đồng thời | Node.js connection overhead cao hơn nhiều so với goroutine (~1KB RAM/conn) |
| VNPay IPN cần respond <50ms | Event loop có thể bị block bởi tác vụ khác cùng lúc, khó đảm bảo SLA cứng |
| ClickHouse batch insert nhiều topic | Cần xử lý đồng thời hiệu quả, Node.js worker threads phức tạp hơn goroutine+channel |
Quyết định
Tạo repo Go riêng với 4 service độc lập (document-worker,
availability-engine, analytics-pipeline, webhook-receiver), chạy song
song NestJS backend, giao tiếp thuần qua Kafka (xem
ADR-0002).
Lựa chọn khác đã cân nhắc
- Worker threads / cluster mode trong NestJS: giữ 1 ngôn ngữ, giảm chi phí học Go, nhưng vẫn không giải quyết được bài toán 10k+ WebSocket connection memory-efficient hay latency cứng <50ms như goroutine — loại.
- Rust thay Go: performance tương đương hoặc tốt hơn, nhưng learning curve cao hơn đáng kể và hệ sinh thái Kafka/ClickHouse/WebSocket cho Go trưởng thành hơn ở thời điểm quyết định — loại.
- Serverless function (Lambda-tương-đương) cho PDF/webhook: giảm vận
hành server, nhưng không phù hợp cho
availability-engine(WebSocket hub cần giữ state kết nối lâu dài) — loại vì không đồng nhất kiến trúc cho cả 4 bucket.
Hệ quả
- Được: mỗi bucket dùng đúng mô hình concurrency phù hợp (goroutine cho WebSocket, channel+ticker cho batch insert); SLA latency cứng (VNPay IPN) đạt được dễ dàng hơn.
- Đánh đổi: thêm 1 ngôn ngữ/repo cần maintain riêng (build pipeline, CI,
dependency management khác NestJS); team phải hiểu cả 2 hệ sinh thái;
payload Kafka phải giữ đồng bộ struct giữa Go (
pkg/events) và NestJS (libs/shared/src/constants/kafka-topics.ts) thủ công — không có schema registry chung.
Liên kết
- Docs liên quan:
README.md(mục "Tại sao cần Go services?") - ADR liên quan: ADR-0002