Skip to main content

การส่ง Campaign แบบ Multicast / เจาะกลุ่มเป้าหมาย

ภาพรวม

Multicast คือการส่ง campaign ไปยัง กลุ่มผู้รับที่ระบุไว้ (audience) หรือถึงสมาชิกทั้งหมดของ OA เท่าที่มีอยู่ในฐานข้อมูล ต่างจาก broadcast ตรงที่ต้องรู้ lineUserId ของผู้รับทุกคน แต่แลกมาด้วยความสามารถในการใช้ merge tag เพื่อใส่ชื่อผู้รับลงในข้อความ และสร้าง tracking link รายบุคคล ได้

นี่คือเส้นทางที่หนักที่สุดในระบบ เพราะจำนวนผู้รับอาจมีตั้งแต่หลักแสนถึงหลายล้านคน จึงต้องมีกลไก concurrency, resume, dry-run และรองรับการเลือกใช้ LINE API ได้ 2 รูปแบบ

Business Flow

  1. รับ payload ที่ประกอบด้วย campaignId, audienceId, organizationId และ lineOaId พร้อมเปิด claim heartbeat ที่อัปเดตทุก 5 นาที

  2. Resolve OA และ validate campaign ด้วยเงื่อนไขเดียวกับ broadcast จากนั้นโหลด quick reply ล่วงหน้าเพียงครั้งเดียว หากโหลดไม่สำเร็จระบบจะส่งข้อความต่อไปโดยไม่มี quick reply แทนที่จะล้มทั้ง campaign

  3. หารายชื่อผู้รับ แยกออกเป็น 3 กรณี

    • มี audienceId และ audience มีไฟล์ CSV ระบุไว้ที่ info.lineUserIdsPathFilename — อ่านไฟล์ CSV จาก S3 แบบแบ่งหน้า ครั้งละ 10,000 รายชื่อจนครบ
    • มี audienceId แต่ไม่มี CSV ซึ่งหมายถึง automated audience — query จากตาราง line_user โดยกรองด้วยเงื่อนไข audience_ids @> to_jsonb($1::int) และ line_oa_id
    • ไม่มี audienceId — เรียก FindAllMemberUID เพื่อดึงสมาชิกทั้งหมดของคู่ lineOaId และ organizationId
  4. ตรวจว่าเนื้อหามี merge tag หรือไม่ โดยดูจาก campaign.has_merge_tags หรือสแกนเนื้อหาโดยตรง แล้วเลือกเส้นทางส่ง

    เส้นทาง A — LINE Multicast API ใช้เมื่อ ไม่มี merge tag และเปิด MULTICAST_USE_BATCH_API

    • สร้าง redirect mapping แบบ shared เพียงครั้งเดียว และ transform message เพียงครั้งเดียว
    • ยิงทีละ batch ขนาด 500 คน โดยใช้ retry key รูปแบบ campaign:<id>:multicast:<batchNo>
    • เป็นเส้นทางที่เร็วและประหยัดจำนวน API call มากที่สุด

    เส้นทาง B — Push Message รายคน เป็นค่าเริ่มต้น และถูกบังคับใช้เมื่อมี merge tag

    • แบ่งผู้รับเป็น batch แล้วในแต่ละ batch จะ bulk-fetch ข้อมูลผู้ใช้ เช่น display_name, firstname, email, custom_attribute เฉพาะกรณีที่มี merge tag เท่านั้น
    • กระจายงานให้ worker ทำงานพร้อมกันตามค่า MULTICAST_CONCURRENCY (ค่าเริ่มต้น 200)
    • สำหรับผู้ใช้แต่ละคน ระบบจะ resolve merge tag → สร้าง tracking link ที่ผูกกับ lineUserId → transform message → แนบ quick reply → เรียก push message
    • ผู้ใช้ที่หาข้อมูลสำหรับ merge tag ไม่เจอจะถูก skip โดยนับไว้ใน skippedCount และเก็บ 100 รายแรกไว้ใน log ตามค่าตั้งใน campaign.skip_merge_tag_missing
  5. รองรับการ resume — บันทึกผู้รับที่ส่งสำเร็จลง Redis set แยกตาม campaign หาก message ถูก redeliver ระหว่างการส่ง คนที่ส่งไปแล้วจะถูกข้ามไปโดยอัตโนมัติ หาก Redis ล่มก็ไม่ block การส่ง

  6. Dry-run — เมื่อเปิด MULTICAST_DRY_RUN ระบบจะทำทุกขั้นตอนตามปกติยกเว้นการยิง LINE API จริง

  7. จบงาน — อัปเดตตาราง campaign ด้วย line_message_object, template_tracking, rich_message_content, end_tracking_date, total_recipient และตั้งสถานะเป็น sent หรือหากล้มเหลวจะเข้า multicastFailed ซึ่งคืนเนื้อหาต้นฉบับ ตั้งสถานะเป็น failed พร้อมบันทึก reason

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

  • internal/linemessageapi/multicast.go
    • MulticastService.HandleLineMulticastRichMessage(ctx, payload) — flow ทั้งหมดของ feature นี้
    • struct MulticastToggles ซึ่งเก็บค่า DryRun, UseBatchAPI และ Concurrency
    • sentSetKey(), isAlreadySent(), markSent() — กลไก resume ผ่าน Redis
    • multicastFailed()
  • internal/linemessageapi/consumer.goConsumer.HandleLineMulticastRichMessage และ withClaimHeartbeat
  • internal/linemessageapi/mergetag.goResolveMergeTags(), extractMergeTagKeys(), hasMergeTags()
  • internal/linemessageapi/extend.gocreateRedirectMappings() ในโหมดรายผู้ใช้
  • internal/csvaudience/csvaudience.go — อ่านไฟล์ CSV ของ audience จาก S3 ผ่าน Count และ Page
  • cmd/worker/integration.go — adapter audienceForLineMessageApi และ lineUserRepoForLineMessageApi
  • Queue: line_multicast_rich_message บน profile main

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

  • แหล่งที่มาของงาน — scanner ของ queue process_campaign หรือ cms-api-go กรณีสั่งส่งทันที
  • ตารางที่เกี่ยวข้องcampaign, rich_message, audience (อ่าน info.lineUserIdsPathFilename), line_user (รายชื่อผู้รับและข้อมูลสำหรับ merge tag), line_oa และกลุ่มตาราง quick reply
  • S3 — เก็บไฟล์ CSV รายชื่อ audience
  • Redis — เก็บ sent-set สำหรับกลไก resume
  • LINE APIPOST /v2/bot/message/multicast สำหรับเส้นทาง A และ POST /v2/bot/message/push สำหรับเส้นทาง B
  • Environment variable ที่ปรับพฤติกรรมได้MULTICAST_DRY_RUN, MULTICAST_USE_BATCH_API, MULTICAST_CONCURRENCY
  • มีเอกสารออกแบบ chunked delivery สำหรับอนาคต ซึ่งจะเพิ่ม queue line_campaign_delivery_batch และตาราง campaign_delivery_batch อยู่ที่ docs/campaign-delivery-tracking-redesign.md ใน repository ของ worker