Skip to main content

การรีเฟรช Audience อัตโนมัติ

ภาพรวม

Audience ประเภท automated คือกลุ่มเป้าหมายที่นิยามด้วยเงื่อนไข filter แทนที่จะเป็นรายชื่อตายตัว จึงต้องคำนวณสมาชิกใหม่เป็นระยะเพื่อให้ข้อมูลทันสมัยอยู่เสมอ

ตรรกะของ filter builder อยู่ที่ฝั่ง cms-api ดังนั้นการคำนวณจริงจึงเกิดขึ้นที่นั่น ส่วน worker ตัวนี้ทำหน้าที่เป็น "ตัวจ่ายงานที่ทนทาน" คือรับข้อความจากคิวแล้วยิง HTTP request ไปเรียก endpoint ภายในของ cms-api

การออกแบบเช่นนี้ให้ประโยชน์สองข้อ ข้อแรกคือได้ retry และ DLQ semantics ของ RabbitMQ มาโดยไม่ต้องเขียนเพิ่ม และข้อที่สองคืองานคำนวณที่ใช้เวลาหลายนาทีจะไม่ไปค้างอยู่ใน HTTP request ของผู้ใช้

Business Flow

  1. รับ payload ชนิด AudienceRefreshPayload ซึ่งมี audienceId และฟิลด์อื่นตามที่ผู้ผลิตงานส่งมา
  2. อ่าน base URL จากตัวแปรสภาพแวดล้อม CMS_API_BASE_URL โดยมีค่าสำรองเป็น http://localhost:3000 และอ่าน key จาก INTERNAL_API_KEY
  3. ยิงคำขอ POST ไปที่ /api/audiences-filter/internal/refresh ของ cms-api
    • แนบ header x-internal-key พร้อมค่าจาก INTERNAL_API_KEY และ Content-Type: application/json
    • body คือ payload ทั้งก้อนที่ส่งต่อไปแบบไม่ดัดแปลง
    • ตั้ง timeout ไว้ที่ 5 นาที ให้ตรงกับ axios timeout ของระบบเดิม เพื่อรองรับ audience ขนาดใหญ่
  4. หากได้ HTTP status ในกลุ่ม 2xx ถือว่าสำเร็จ บันทึก log แล้วตอบ ack
  5. หากเกิด transport error หรือได้ status ที่ไม่ใช่ 2xx จะบันทึก log แล้วคืนค่า error ให้ชั้น mq เป็นผู้ตัดสินใจ โดยกรณี transient เช่น 5xx หรือ timeout จะถูก retry ตามลำดับ 1 วินาที 4 วินาที และ 9 วินาที ก่อนส่งเข้า DLQ

ไฟล์และฟังก์ชันหลัก

  • internal/audience/refresh_consumer.go
    • RefreshConsumer.OnAudienceRefresh(ctx, body) — handler หลักของงานนี้
    • NewRefreshConsumer(cfg, log) และ Register(reg, cfg)
    • ค่าคงที่ refreshPath มีค่าเป็น /api/audiences-filter/internal/refresh และ refreshTimeout มีค่าเป็น 5 นาที
    • logRefreshFailed()
  • internal/audience/payloads.go — นิยามชนิด AudienceRefreshPayload
  • cmd/worker/main.go — ลงทะเบียน consumer ใน runMain() ด้วย audience.NewRefreshConsumer(cfg, log).Register(reg, cfg)
  • คิวที่เกี่ยวข้อง: audience_refresh (runtime profile main)

จุดเชื่อมต่อกับ Service อื่น

  • ต้นทางของงาน — cms-api-go หรือ cron ฝั่ง CMS ที่ต้องการให้คำนวณสมาชิก audience ใหม่
  • ปลายทางที่เรียกออกไป — endpoint ภายในของ cms-api-go คือ POST /api/audiences-filter/internal/refresh ซึ่งป้องกันด้วย header x-internal-key
  • ตัวแปรสภาพแวดล้อมCMS_API_BASE_URL และ INTERNAL_API_KEY
  • ไม่แตะฐานข้อมูลและไม่เรียก LINE API โดยตรง เพราะเป็น consumer แบบ forward ล้วน
  • ผลลัพธ์ปลายทางline_user.audience_ids และ audience.info จะถูกอัปเดตโดย cms-api เป็นผู้เขียนเอง