ระบบเฝ้าระวัง Dead-letter Queue (DLQ Monitor)
ภาพรวม
เมื่อ message ใดถูก retry ครบ 3 รอบแล้วยังล้มเหลว หรือเป็น permanent error ตั้งแต่แรก message นั้นจะถูก dead-letter ลง <queue>.dlq ปัญหาคือถ้าไม่มีใครดูแล message เหล่านั้นจะกองสะสมอยู่เงียบ ๆ โดยไม่มีใครรับรู้
DLQ Monitor คือ consumer พิเศษที่รันอยู่บน profile main ทำหน้าที่ subscribe DLQ ทุกตัว ที่อยู่ในชุดที่ต้อง monitor, log รายละเอียดของ message ที่ตายไว้ครบถ้วน (payload, x-death, x-retry-count) และรวบรวมเป็น batch เพื่อยิงแจ้งเตือนเข้า chat webhook แบบมี cooldown ป้องกันการ spam
Business Flow
- เมื่อ
runMainเริ่มทำงาน ระบบจะสร้างDLQMonitorแล้วรันเป็น goroutine แยกจาก registrar หลัก - Monitor เปิด consumer 1 ตัวต่อ 1 DLQ ตามรายการใน
MonitoredDLQQueuesซึ่งมี 37 queue (คือAllQueuesทั้งหมดหักด้วยmessage_received_triggerที่จงใจไม่ monitor) - ทุกครั้งที่มี message ตกลง DLQ ระบบจะ
- แกะและ log ชื่อ queue ต้นทาง, payload, error รวมถึง header
x-deathและx-retry-count - เก็บรายการนั้นลง
pendingAlertsโดยบันทึก queue, payload และ error
- แกะและ log ชื่อ queue ต้นทาง, payload, error รวมถึง header
- หากเวลาผ่านไปเกิน
DLQ_ALERT_COOLDOWN_MS(ค่าเริ่มต้น 5 นาที) นับจาก alert ครั้งก่อน ระบบจะรวมpendingAlertsทั้งหมดยิงเป็นข้อความเดียวไปที่DLQ_ALERT_WEBHOOK_URLแล้วเคลียร์ buffer - Monitor จะ ack เสมอ ไม่ว่าจะ parse payload สำเร็จหรือไม่ เพื่อไม่ให้เกิด redelivery loop ที่ไม่มีวันจบใน DLQ
ไฟล์และฟังก์ชันหลัก
internal/mq/dlqmonitor.goClient.NewDLQMonitor()— สร้าง monitor จาก config (DLQ_ALERT_WEBHOOK_URL,DLQ_ALERT_COOLDOWN_MS)DLQMonitor.Run(ctx)— เปิด consumer ของทุก DLQ พร้อมกันDLQMonitor.consume(ctx, dlqQueue, suffix)— loop consume ต่อ 1 DLQdlqAlert— struct แทน alert หนึ่งรายการ
internal/mq/topology.go—MonitoredDLQQueues()ซึ่งเป็นชุด queue ที่ถูก monitorcmd/worker/main.go— ส่วนของrunMain()ที่สร้างและ start monitor- Queue ที่ subscribe คือ
<queue>.dlqทุกตัว โดย suffix มาจากRABBITMQ_DLQ_SUFFIX(ค่าเริ่มต้น.dlq) และ bind อยู่กับ exchangeline_exchange_dlq
จุดเชื่อมต่อกับ Service อื่น
- RabbitMQ — consume จาก DLQ ทั้งหมด โดยต้อง assert topology ให้เรียบร้อยก่อน
- Chat webhook (
DLQ_ALERT_WEBHOOK_URL) — ยิง HTTP POST ด้วย body รูปแบบ{"text": ...}ซึ่งรองรับทั้ง Google Chat และ Slack โดยตั้ง client timeout ไว้ 5 วินาที หากไม่ได้ตั้งค่า URL นี้ monitor จะทำงานแบบ log อย่างเดียวโดยไม่ยิง alert - ไม่มีการเข้าถึงฐานข้อมูล — feature นี้เป็นงาน observability ล้วน ๆ
- เกี่ยวข้องโดยตรงกับโครงสร้าง Queue RabbitMQ และกลไก Retry / Dead-letter