Vận hành
1. Triển khai
| Thuộc tính | Giá trị |
|---|---|
| Image | registry/nx-seller-sale:<tag> |
| Container Port | 3000 |
| External Port | 31030 |
| Snowflake ID | 3 |
| Replicas (mặc định) | 1 (dev) / 2+ (staging+) |
| Resources (req/lim) | 200m / 1 CPU, 512Mi / 2Gi memory |
| HPA target | CPU 70% (khi scale) |
| Migration mode | RUN_MODE=migrate job trước rollout; on-boot cho dev |
| Live probe | GET /v1/api/sale/healthz |
| Ready probe | GET /v1/api/sale/readyz |
Traefik routing labels
yaml
labels:
- "traefik.enable=true"
- "traefik.http.routers.sale.rule=PathPrefix(`/v1/api/sale`)"
- "traefik.http.services.sale.loadbalancer.server.port=3000"Hạ tầng yêu cầu
| Phụ thuộc | Lý do |
|---|---|
| PostgreSQL | Datastore chính (schema sale, allocation) |
| Kafka brokers | Bắt buộc — producer dùng cho thông báo downstream |
| Redis | Tùy chọn — auth cache; service vẫn start không có nó |
@nx/identity đến được | Xác minh JWKS trên mỗi JWT |
@nx/pricing đến được | Checkout fail nếu không có pricing service |
@nx/mq-pay đến được | Nguồn webhook — phải cùng mạng nội bộ |
@nx/signal đến được | Fanout WebSocket |
2. Observability
| Tín hiệu | Nguồn | Tìm ở đâu |
|---|---|---|
| Logs | stdout (IGNIS structured logger, định dạng key: %s) | kubectl logs deploy/sale / Loki |
| Health | GET /v1/api/sale/healthz, GET /readyz | Gateway portal |
| OpenAPI live spec | GET /v1/api/sale/doc/openapi.json | Gateway portal explorer |
| Metrics | Traefik gateway :30800 (Prometheus scrape) | Grafana — gateway dashboard |
Trường log quan trọng
| Trường | Nguồn | Ghi chú |
|---|---|---|
requestId | header X-Request-Id | Lan truyền liên service |
userId | JWT subject | — |
merchantId | scope request | — |
saleOrderId | service operations | Quan trọng cho trace |
kitchenTicketItemId | flow kitchen ticket | |
topic / partition / offset | log Kafka emit |
Truy vấn log hữu ích
| Câu hỏi | Truy vấn |
|---|---|
| Webhook routing failures | level=error AND PaymentWebhookService |
| Lỗi pricing service khi checkout | level=error AND PricingNetworkService |
| Order add-item lock waits | SELECT FOR UPDATE AND wait |
| Kitchen status mismatch | KITCHEN_TICKET_ITEM_STATUS_CHANGED AND unexpected |
3. Bảo mật
| Mối quan tâm | Giảm thiểu |
|---|---|
| AuthN | JWT (ES256, JWKS lấy từ identity khi boot + theo yêu cầu) |
| AuthZ | Casbin qua PolicyDefinitionService; permission cache trong Redis (hoặc in-memory) |
| Trust webhook | /webhooks/payment không có auth — dựa vào Cilium network policy chỉ cho phép MQ-Pay → sale |
| Service-to-service | Strategy BASIC cho call liên package |
| Secrets | K8s Secret mount như env (APP_ENV_DB_URL, APP_ENV_KAFKA_SASL_PASSWORD, v.v.) |
| TLS | Kết thúc tại Nginx → Traefik → service plaintext (intra-cluster) |
| Rate limit | Middleware Traefik (mặc định 100 rps/IP); endpoint webhook có thể có quota riêng |
| Network policy | Cilium — chỉ cho phép gateway + Kafka + Postgres + Redis + identity + pricing + MQ-Pay |
| Soft-delete | deletedAt trên tất cả thực thể sale; archive thay vì hard-delete |
| Bảo vệ race | SELECT ... FOR UPDATE trên row order khi add-item, checkout, merge, split |
4. Runbook
4.1 Phân loại Alert
| Alert | Trigger | Kiểm tra | Sửa | Escalate |
|---|---|---|---|---|
SaleHighErrorRate | 5xx >5% trong 5m | kubectl logs deploy/sale | grep level=error | xác định endpoint lỗi; rollback deploy gần nhất nếu vừa diễn ra | on-call backend |
SaleWebhookFailures | webhook 5xx errors tăng | grep PaymentWebhookController | kiểm tra schema drift của payload; kiểm tra trạng thái sister-service | on-call backend + payment team |
SaleCheckoutFailures | spike /checkout 4xx/5xx | grep PricingNetworkService; kiểm tra health pricing service | restart pricing svc; tăng replica pricing | on-call backend |
SaleKafkaProduceFailure | log error KafkaProducer | bun -e 'cluster status' | kiểm tra health broker, SASL creds | on-call SRE |
SaleStuckOrder | order ở PROCESSING >1h | DB query WHERE status='PROCESSING' AND processingAt < now() - interval '1h' | kiểm tra MQ-Pay attempts; hủy thủ công nếu cũ | on-call backend |
SaleSessionLeak | open PosSession per device >24h | DB query | đóng thủ công + đối chiếu | on-call ops |
SaleAllocationStuck | AllocationUsage.ACTIVE >24h sau hủy | DB query | cascade hủy thủ công | on-call backend |
4.2 Thao tác phổ biến
| Thao tác | Lệnh |
|---|---|
| Tail log | kubectl logs -n <ns> -f deploy/sale |
| Chạy migration thủ công | kubectl exec -it deploy/sale -- bun run migrate |
| Chuyển trạng thái order kẹt thủ công | DB UPDATE (sau backup) — yêu cầu phê duyệt senior |
| Replay sự kiện webhook | Trigger MQ-Pay redelivery qua admin API của nó |
| Kiểm tra subscriber WebSocket | Admin panel @nx/signal |
| Audit lý do hủy | SELECT cancellationReason, count(*) FROM "SaleOrder" WHERE cancelledAt > ... GROUP BY 1 |
4.3 Kịch bản phục hồi
| Kịch bản | Phục hồi |
|---|---|
| Service crash giữa checkout | Order vẫn DRAFT (transaction rollback); UI prompt retry |
| Webhook đã đến nhưng Kafka emit fail | _enqueuePaymentSuccess log lỗi; tool replay thủ công publish từ snapshot order. Inventory chưa bị trừ cho đến khi replay. |
| Webhook redelivery duplicate | Idempotency handler: skip no-op nếu order đã ở status target |
| Kẹt PROCESSING sau timeout MQ-Pay | Hủy thủ công → status CANCELLED → AllocationUsage hủy theo |
| Tổng sai sau merge/split | Dùng jsonb transferHistory trên SaleOrderItem để audit; rollback qua OrderMergeService.rollback hoặc op ngược của OrderSplitService |
| Mất POS session | closeRecountCount theo dõi số lần đếm lại; đóng thủ công + đối chiếu |
5. Cross-Service Runbook
Cho sự cố trải nhiều service, xem runbook/ trung tâm:
6. Trang liên quan
- Cấu hình
- API Sự kiện — constant topic Kafka cho lệnh replay
- Tích hợp — mạng sister-service
- Quyết định