diff --git a/apps/web/src/server/service/campaign-service.ts b/apps/web/src/server/service/campaign-service.ts index 5a109993..da5d7cd9 100644 --- a/apps/web/src/server/service/campaign-service.ts +++ b/apps/web/src/server/service/campaign-service.ts @@ -1249,7 +1249,7 @@ export class CampaignBatchService { await this.batchQueue.add( `campaign-${campaignId}`, { campaignId, teamId }, - { jobId: `campaign-batch:${campaignId}`, ...DEFAULT_QUEUE_OPTIONS }, + { jobId: `campaign-batch-${campaignId}`, ...DEFAULT_QUEUE_OPTIONS }, ); } } diff --git a/apps/web/src/server/service/campaign-service.unit.test.ts b/apps/web/src/server/service/campaign-service.unit.test.ts index 2fe049ec..52a5d420 100644 --- a/apps/web/src/server/service/campaign-service.unit.test.ts +++ b/apps/web/src/server/service/campaign-service.unit.test.ts @@ -28,6 +28,7 @@ const { mockDb, mockTx, mockUpdateContactSubscription } = vi.hoisted(() => { findUnique: vi.fn(), }, campaign: { + findUnique: vi.fn(), update: vi.fn(), }, }, @@ -35,6 +36,10 @@ const { mockDb, mockTx, mockUpdateContactSubscription } = vi.hoisted(() => { }; }); +const { mockQueueAdd } = vi.hoisted(() => ({ + mockQueueAdd: vi.fn(), +})); + vi.mock("~/server/db", () => ({ db: mockDb, })); @@ -55,7 +60,7 @@ vi.mock("~/server/service/contact-service", () => ({ vi.mock("bullmq", () => ({ Queue: class { - add = vi.fn(); + add = mockQueueAdd; }, Worker: class {}, })); @@ -92,6 +97,7 @@ vi.mock("~/server/logger/log", () => ({ })); import { + CampaignBatchService, recordCampaignContactFailure, subscribeContact, unsubscribeContact, @@ -196,6 +202,31 @@ describe("recordCampaignContactFailure", () => { }); }); +describe("CampaignBatchService", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("queues batches with a BullMQ-safe custom job ID", async () => { + mockDb.campaign.findUnique.mockResolvedValue({ + lastSentAt: null, + batchWindowMinutes: 0, + status: "SCHEDULED", + }); + + await CampaignBatchService.queueBatch({ + campaignId: "campaign_1", + teamId: 7, + }); + + expect(mockQueueAdd).toHaveBeenCalledWith( + "campaign-campaign_1", + { campaignId: "campaign_1", teamId: 7 }, + expect.objectContaining({ jobId: "campaign-batch-campaign_1" }), + ); + }); +}); + describe("campaign contact subscription changes", () => { beforeEach(() => { vi.clearAllMocks();