Skip to main content

Broadcast Campaign Delivery (reaching every friend of the OA)

Overview

A broadcast sends a campaign's rich message to every friend of the LINE OA through a single call to the LINE Broadcast API, with no recipient list required. That makes it the cheapest and fastest delivery path, in contrast to multicast, which has to work through the audience group by group.

This job consumes from the line_broadcast_rich_message queue. It validates the campaign and the OA, builds tracking links for every URL and image in the message, transforms the message objects, calls the LINE Broadcast API, and writes the outcome back to the campaign table.

Business Flow

  1. Receive a payload containing campaignId, audienceId, organizationId, and lineOaId.
  2. Start the claim heartbeat — a background ticker refreshes campaign.claimed_at to the current time every 5 minutes during the send, guarded by status='sending', so the reaper cannot reclaim the campaign mid-flight.
  3. Validate the campaignGetCampaignAndValidate loads the campaign together with rich_message.content via a LEFT JOIN, respecting soft deletes.
    • A draft or cancel status is flipped to failed and an error is raised.
    • Any status other than sending indicates a duplicate or late redelivery, so the message is discarded quietly as a permanent error with no republish.
  4. Snapshot the original content — clone the original rich message content so it can be restored if the send fails.
  5. Validate the OAGetLineOAAndValidate resolves the OA and returns a verified or refreshed channelAccessToken. If the OA is not active, the campaign is flipped to failed.
  6. Build redirect mappings — extract every URL and image URL from the content and replace them with tracked URLs.
    • Broadcasts use shared tokens and links, not bound to a userId, since there is no way to know in advance who will see the message.
    • The path taken depends on CAMPAIGN_REDIRECT_MODE: the legacy universal-redirect service or the builtin encrypted token (see Campaign Tracking Links).
  7. Transform the messageTransformMessageObjects swaps the original URLs for tracked ones throughout the message structure and attaches the quick reply if the campaign references a quick_reply_id.
  8. Call the LINE Broadcast API with a retry key attached.
  9. Write back the result — update campaign with line_message_object, template_tracking, rich_message_content, end_tracking_date (start_date plus 90 days), total_recipient, and set the status to sent.
  10. On failurebroadcastFailed restores the original content, sets the status to failed, and records a reason. Validation and setup errors are logged and then swallowed (returning nil so the message is acked), matching the behaviour of the legacy system.

Key Files & Functions

  • internal/linemessageapi/broadcast.go
    • BroadcastService.HandleLineBroadcastRichMessage(ctx, payload)
    • broadcastFailed() and endTrackingDateFrom(), which defines the 90-day tracking window
    • The LineBroadcastRichMessagePayload struct
  • internal/linemessageapi/consumer.goConsumer.HandleLineBroadcastRichMessage and withClaimHeartbeat(), using a claimHeartbeatInterval of 5 minutes
  • internal/linemessageapi/extend.goextendService.createRedirectMappings(), buildBuiltinMappings(), getGaSettings(), getLineLiffId()
  • internal/linemessageapi/util.goTransformMessageObjects(), ExtractUrls(), ExtractImageUrls()
  • internal/quickreply/attach.goLoadItems() for attaching quick replies
  • internal/line/messaging.goClient.Broadcast(messages, retryKey)
  • Queue: line_broadcast_rich_message on the main profile

Connections to Other Services

  • Job sources — the process_campaign scanner (see Campaign Schedule Dispatch), or cms-api-go when the user sends immediately
  • Tablescampaign (read and update), rich_message (content and quick_reply_id), line_oa (token), quick_reply and quick_reply_item
  • LINE APIPOST /v2/bot/message/broadcast to send, and GET /v2/bot/insight/followers to count followers for the total recipient figure
  • Redirect service and campaignlink — used to mint tracked URLs
  • Downstream effects — link taps insert into tracking_log, which fires a Postgres trigger into campaign_click_trigger, and the statistics are computed by Campaign Stat Calculation