Skip to content

ADR-0003. Sự kiện thanh toán MQ-Pay đến qua HTTP webhook, không hỏi vòng

TrườngGiá trị
Trạng tháiAccepted
Ngày2026-02-15
Người quyết địnhPhat Nguyen
Thay thế cho-

Bối cảnh

  • Sau khi khách hoàn tất thanh toán qua MQ-Pay (lớp trừu tượng cho VNPay và các cổng khác), sale cần cập nhật trạng thái đơn, allocation usage, điểm khách hàng, và phát Kafka cho các service phía sau.
  • Có hai cách để sale biết được kết quả thanh toán:
    1. Hỏi vòng MQ-Pay theo chu kỳ.
    2. Webhook - MQ-Pay gửi POST tới sale.
  • Hỏi vòng vừa lãng phí vừa độ trễ cao. Trải nghiệm POS thời gian thực cần cập nhật trạng thái tức thì.

Quyết định

MQ-Pay gửi POST tới POST /v1/api/sale/webhooks/payment với các loại sự kiện mq-pay:attempt.{success,failed,expired,cancelled}mq-pay:transaction.{settled,cancelled}. Sale xử lý sự kiện, chuyển trạng thái, rồi phát KafkaTopics.PAYMENT_SUCCESS sau khi commit.

Sale không hỏi vòng MQ-Pay. Webhook là tín hiệu thanh toán đầu vào duy nhất.

Endpoint webhook không có xác thực. Độ tin cậy được bảo đảm bằng Cilium network policy: chỉ MQ-Pay mới truy cập được /webhooks/payment qua mạng nội bộ.

Hệ quả

ƯuNhược
Trạng thái đơn theo thời gian thực (dưới một giây sau khi trả tiền)Điểm hỏng đơn lẻ - nếu webhook không tới được sale, trạng thái sẽ kẹt
Không hỏi vòng lãng phíBảo mật webhook dựa vào network policy, không phải header xác thực
MQ-Pay tự động thử lại với lỗi 5xxSale phải idempotent khi bị thử lại (handler dừng sớm nếu đã ở trạng thái đích)
Tách sale khỏi các đặc thù riêng của nhà cung cấp thanh toánRanh giới tin cậy mang tính ngầm định; người vận hành mới phải hiểu điều này

Khôi phục

  • Nếu webhook hỏng liên tục, MQ-Pay đưa sự kiện vào queue và thử lại.
  • Người vận hành có thể tự tay kích hoạt gửi lại qua trang admin của MQ-Pay.
  • Nhờ tính idempotent của sale, việc gửi lại là an toàn.

Các phương án đã cân nhắc

Phương ánƯuNhượcLý do từ chối
Hỏi vòng MQ-Pay mỗi N giâyMô hình kéo; sale tự kiểm soát thời điểmLãng phí; độ trễ cao; không mở rộng tới hàng nghìn đơnTrải nghiệm POS quá chậm
Kết hợp: webhook + hỏi vòng dự phòng cho đơn bị kẹtBền bỉThêm phức tạp; rủi ro nhận sự kiện hai lầnCó thể bổ sung sau nếu webhook tỏ ra không đáng tin
Webhook kèm xác thực bằng khoá bí mật chungBảo mật mạnh hơnTốn công vận hành để xoay vòng khoá bí mật; MQ-Pay vốn đã ở mạng tin cậyNetwork policy là đủ với mức độ đe doạ hiện tại

Tham chiếu

  • sale/src/common/webhook-types.ts:9 (PaymentWebhookEventTypes)
  • sale/src/controllers/payment-webhook/payment-webhook.controller.ts
  • sale/src/services/payment-webhook.service.ts (bộ điều phối)
  • sale/src/services/sale-order-payment-webhook.service.ts (các handler sự kiện)

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.