feat(campaign-packer): paginate audience and publish campaigns.send (EVO-1216)#39
Open
nickoliveira23 wants to merge 1 commit into
Open
feat(campaign-packer): paginate audience and publish campaigns.send (EVO-1216)#39nickoliveira23 wants to merge 1 commit into
nickoliveira23 wants to merge 1 commit into
Conversation
…EVO-1216) Implements story 4.2: extends CampaignPackerService.pack() to paginate the resolved audience into batches and publish one `campaigns.send` message per page. Empty audiences publish a single `campaigns.tracked` with completed:true so the CampaignWorkflow closes instead of hanging. - PaginationService: pure, O(n) split into 1-based pages (page ≤ totalPages) - CampaignPackerService: load contactIds, branch empty vs paginate+publish; map Campaign channelType (Channel::*) to the send-contract transport id; resolve the A-variant message template; CAMPAIGN_PACKER_BATCH_SIZE (default 1000) - CampaignNotConfiguredError (TerminalError) for a campaign missing channel/template - specs: pagination unit + packer integration with a broker mock (15 examples) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @nickoliveira23, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements story 4.2 (Campaign Dispatch Pipeline): extends
CampaignPackerService.pack()(from 4.1 / EVO-1215) to paginate the resolved audience and publish onecampaigns.sendmessage per page, enabling the horizontal fan-out of thecampaign-sender(4.3).PaginationService: pure, O(n)split(contactIds, batchSize)into 1-based pages (page ≤ totalPages).pack()now: loads the campaign (with templates), computes audience, loads the persisted (PENDING)contactIds, then:campaigns.trackedwith{page:0, sentCount:0, failedCount:0, completed:true}+ logscampaign has no contacts(soCampaignWorkflowcloses instead of hanging);templateId(A-variant) +channelType, splits, and publishes onecampaigns.sendper page.channelTypemapping: CRM stores the Rails STI name (Channel::Email); the broker contract uses the transport id (email). Bridged at the publish boundary.CAMPAIGN_PACKER_BATCH_SIZEenv (default 1000), clamped against 0/NaN.CampaignNotConfiguredError extends TerminalErrorfor a campaign missing channel type or message template (drops, no requeue loop).correlationIdpropagated from the incomingcampaigns.packpayload to every published message.Security
TerminalError→ terminal drop, never a redelivery loop.Test plan
evo-flow: npm run typecheck— cleanevo-flow: npx jest src/runners/campaign-packer/services/pagination.service.spec.ts src/runners/campaign-packer/services/campaign-packer.service.spec.ts— 15 examples, 0 failuresevo-flow: npx eslint <changed .ts>— production files clean (specs follow the existing campaign-packer spec baseline)Covers ACs: split math at 2500→[1000,1000,500] / exact-multiple (AC1/AC3), 1500→2 pages (AC3), empty→tracked+warn (AC2), payload validated against the strict
campaigns.sendzod contract + channelType mapping (AC4).Notes
clearAudienceon re-pack this opens a double-send window. By design thecampaign-sender(4.3) dedups viaCampaignContact.status; broker-level redelivery backstop is tracked in EVO-1677. Out of scope here.loadContactIdsreads the full PENDING audience viafind({ select: { contactId } }); at ~1M contacts agetRawManyprojection would avoid entity hydration — optional perf follow-up, in-memory split is the approach the card prescribes.campaign.paginatedstructured log was added for observability.Changed Files
src/runners/campaign-packer/services/pagination.service.ts(new)src/runners/campaign-packer/services/pagination.service.spec.ts(new)src/runners/campaign-packer/services/campaign-packer.service.tssrc/runners/campaign-packer/services/campaign-packer.service.spec.tssrc/runners/campaign-packer/errors/campaign-not-configured.error.ts(new)src/runners/campaign-packer/campaign-packer.module.tsLinked Issue