eletrotupi / tcc/ api/src/lib/queue/WorkerRegistry.ts8480619e654d675a3b0327e5df6b8b94dab2c32b
2.2 KB | 72 lines Raw
1
import { Worker, WorkerOptions, Processor } from "bullmq";
2
import { getQueue, QueueName } from "@app/lib/queue/QueueRegistry";
3
import { mailProcessor } from "@app/lib/queue/processors/mail";
4
import { insightProcessor } from "@app/lib/queue/processors/insights";
5
import { medicineReminderProcessor } from "@app/lib/queue/processors/medicineReminders";
6
import { dailyReminderProcessor } from "@app/lib/queue/processors/dailyReminders";
7
import { exportProcessor } from "@app/lib/queue/processors/exports";
8
import { InsightJobName } from "@app/lib/queue/types";
9

10
type ProcessorMap = Record<QueueName, Processor>;
11

12
const processorMap: ProcessorMap = {
13
  mail: mailProcessor,
14
  insights: insightProcessor,
15
  "medicine-reminders": medicineReminderProcessor,
16
  "daily-reminders": dailyReminderProcessor,
17
  exports: exportProcessor,
18
};
19

20
// Per-queue concurrency
21
// TODO: When we process images, we need to bump for that queue
22
const concurrencyMap: Record<QueueName, number> = {
23
  mail: 10,
24
  insights: 5,
25
  "medicine-reminders": 5,
26
  "daily-reminders": 5,
27
  exports: 5,
28
};
29

30
const workers: Worker[] = [];
31

32
export function bootWorkers(): void {
33
  console.log("Booting workers...");
34
  for (const [name, processor] of Object.entries(processorMap)) {
35
    const queueName = name as QueueName;
36

37
    console.log(`Worker ${queueName} booting...`);
38
    const worker = new Worker(queueName, processor, {
39
      connection: {
40
        host: process.env.VALKEY_HOST,
41
        port: Number(process.env.VALKEY_PORT),
42
      },
43
      concurrency: concurrencyMap[queueName],
44
    } satisfies WorkerOptions);
45

46
    worker.on("failed", (job, err) => {
47
      console.error(`[${queueName}] job ${job?.id} failed:`, err.message);
48
    });
49

50
    worker.on("error", (err) => {
51
      console.error(`[${queueName}] worker error:`, err.message);
52
    });
53

54
    workers.push(worker);
55
  }
56
}
57

58
export async function scheduleInsights(): Promise<void> {
59
  const queue = getQueue("insights");
60
  await queue.add(
61
    InsightJobName.FanOut,
62
    {},
63
    {
64
      repeat: { pattern: "0 3 * * 1" }, // Mondays at 3am
65
      jobId: "insight-fan-out-weekly", // prevents duplicate repeatable jobs on restart
66
    },
67
  );
68
}
69

70
export async function closeAllWorkers(): Promise<void> {
71
  await Promise.all(workers.map((w) => w.close()));
72
}