Multicast / Targeted Campaign Delivery
Overview
Multicast sends a campaign to a specific set of recipients (an audience), or to every OA member recorded in the database. Unlike broadcast, it requires knowing each recipient's lineUserId — but in exchange it supports merge tags for personalising the message and per-user tracking links.
This is the heaviest path in the system: recipient counts range from hundreds of thousands to several million. It therefore includes concurrency control, resume support, a dry-run mode, and a choice between two LINE API strategies.
Business Flow
-
Receive a payload containing
campaignId,audienceId,organizationId, andlineOaId, and start the claim heartbeat that refreshes every 5 minutes. -
Resolve the OA and validate the campaign using the same rules as broadcast, then load the quick reply once up front. If that load fails, delivery continues without the quick reply rather than failing the whole campaign.
-
Resolve the recipient list, which falls into three cases:
audienceIdis set and the audience has a CSV file atinfo.lineUserIdsPathFilename— read the CSV from S3 in pages of 10,000 IDs until exhausted.audienceIdis set but there is no CSV, meaning an automated audience — query theline_usertable filtered byaudience_ids @> to_jsonb($1::int)andline_oa_id.- No
audienceId— callFindAllMemberUIDto fetch every member of thelineOaIdandorganizationIdpair.
-
Determine whether the content uses merge tags, either from
campaign.has_merge_tagsor by scanning the content, then choose a delivery path.Path A — the LINE Multicast API, used when there are no merge tags and
MULTICAST_USE_BATCH_APIis enabled.- Build the shared redirect mappings once and transform the message once.
- Send in batches of 500 recipients, using retry keys of the form
campaign:<id>:multicast:<batchNo>. - This is the fastest path and consumes the fewest API calls.
Path B — per-user push messages, the default, and mandatory when merge tags are present.
- Split recipients into batches and, within each batch, bulk-fetch user data such as
display_name,firstname,email, andcustom_attribute— but only when merge tags are actually in use. - Distribute the work across concurrent workers according to
MULTICAST_CONCURRENCY(default 200). - For each user: resolve merge tags, mint a tracking link bound to their
lineUserId, transform the message, attach the quick reply, and call push message. - Users whose merge tag data cannot be found are skipped, counted in
skippedCount, with the first 100 recorded in the log, governed bycampaign.skip_merge_tag_missing.
-
Resume support — successfully delivered recipients are recorded in a per-campaign Redis set. If the message is redelivered mid-send, already-delivered users are skipped automatically. A Redis outage does not block delivery.
-
Dry-run — with
MULTICAST_DRY_RUNenabled, every step runs normally except the actual LINE API call. -
Completion — update the
campaigntable withline_message_object,template_tracking,rich_message_content,end_tracking_date,total_recipient, and set the status tosent. On failure,multicastFailedrestores the original content, sets the status tofailed, and records areason.
Key Files & Functions
internal/linemessageapi/multicast.goMulticastService.HandleLineMulticastRichMessage(ctx, payload)— the entire flow- The
MulticastTogglesstruct holdingDryRun,UseBatchAPI, andConcurrency sentSetKey(),isAlreadySent(),markSent()— the Redis-backed resume mechanismmulticastFailed()
internal/linemessageapi/consumer.go—Consumer.HandleLineMulticastRichMessageandwithClaimHeartbeatinternal/linemessageapi/mergetag.go—ResolveMergeTags(),extractMergeTagKeys(),hasMergeTags()internal/linemessageapi/extend.go—createRedirectMappings()in per-user modeinternal/csvaudience/csvaudience.go— reads audience CSV files from S3 throughCountandPagecmd/worker/integration.go— theaudienceForLineMessageApiandlineUserRepoForLineMessageApiadapters- Queue:
line_multicast_rich_messageon themainprofile
Connections to Other Services
- Job sources — the
process_campaignscanner, or cms-api-go when the user sends immediately - Tables —
campaign,rich_message,audience(readinginfo.lineUserIdsPathFilename),line_user(recipient list and merge tag data),line_oa, and the quick reply tables - S3 — stores the audience CSV files
- Redis — holds the sent-set used for resume
- LINE API —
POST /v2/bot/message/multicastfor Path A andPOST /v2/bot/message/pushfor Path B - Behavioural environment variables —
MULTICAST_DRY_RUN,MULTICAST_USE_BATCH_API,MULTICAST_CONCURRENCY - A future chunked-delivery design, adding the
line_campaign_delivery_batchqueue and acampaign_delivery_batchtable, is documented indocs/campaign-delivery-tracking-redesign.mdin the worker repository