ADR-0004. Trạng thái OTP trong Redis (theo TTL), không lưu PostgreSQL
| Trường | Giá trị |
|---|---|
| Trạng thái | Accepted |
| Ngày | 2026-02-12 |
| Người quyết định | Phat Nguyen |
| Thay thế | - |
Bối cảnh
- Luồng OTP có trạng thái tạm thời với ngữ nghĩa TTL chặt chẽ:
- Mã đã hash (TTL 10 phút)
- Bộ đếm số lần thử (khoá sau 5 lần thử)
- Thời gian chờ sau mỗi lần gửi (60s)
- Bộ đếm hạn ngạch hàng ngày
- Lưu trong PostgreSQL nghĩa là: dọn dẹp TTL kiểu cron, khoá khi tăng bộ đếm, bảng phình to vì hàng triệu bản ghi đã hết hạn.
Quyết định
Toàn bộ trạng thái OTP lúc chạy nằm trong Redis với key được phân vùng tên:
| Key | TTL | Mục đích |
|---|---|---|
{ns}:otp:{identifier} | 5-15 phút | Mã đã hash |
{ns}:lock:{identifier} | 10-15 phút | Khoá tài khoản |
{ns}:session:{token} | 1-24 giờ | Token phiên đã xác thực |
{ns}:cooldown:{identifier} | 60s | Thời gian chờ gửi lại |
{ns}:daily:{identifier} | 24 giờ | Hạn ngạch hàng ngày |
Namespaces: verify-email, verify-phone, forgot-password, phone-auth, add-phone, add-email.
Mã được hash bằng Bun.password trước khi lưu.
Hệ quả
| Ưu | Nhược |
|---|---|
| Hết hạn theo TTL - không cần job dọn dẹp | Luồng OTP hỏng hoàn toàn nếu Redis ngừng hoạt động |
| INCR liền mạch cho bộ đếm | Trạng thái chỉ tạm thời - mất khi xoá sạch Redis |
| Đọc dưới mili-giây | Hash mã làm tăng CPU mỗi lần xác minh |
| Không phình bảng PostgreSQL | Dấu vết kiểm toán các lần thử OTP không được lưu |
Tình huống lỗi
Nếu Redis không khả dụng:
- Yêu cầu OTP mới trả về
503 Service Unavailable - Việc xác minh JWT hiện có vẫn hoạt động (cache nằm phía service anh em)
- Token OTP đã phát trước đó vẫn xác minh được nếu được cache phía client, nhưng xác minh phía server thất bại
Phương án đã xem xét
| Phương án | Ưu | Nhược | Lý do từ chối |
|---|---|---|---|
| PostgreSQL với dọn dẹp cron | Dấu vết kiểm toán | Tranh chấp khoá trên bộ đếm; độ trễ khi dọn dẹp; phình bảng | Sai đánh đổi |
| Chỉ trong bộ nhớ (mỗi instance) | Nhanh nhất | Không sống sót qua lần khởi động lại; không mở rộng ra N pod | Vận hành mong manh |
| Lai (ghi DB + cache Redis) | Kiểm toán + tốc độ | Phối hợp ghi kép | Phức tạp không đáng |
Tham chiếu
BaseOTPBasedMFAService(lớp cơ sở trừu tượng)EmailOtpService,PhoneOtpService(lớp cụ thể)BindingKeys.APPLICATION_REDIS_BULLMQ