eletrotupi / tcc/ api/src/lib/queue/WorkerRegistry.ts9879196f5eaf3242b6682db701cf97ceb37b4487
2.1 KB | 69 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 { InsightJobName } from "@app/lib/queue/types";
8

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

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

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

27
const workers: Worker[] = [];
28

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

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

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

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

51
    workers.push(worker);
52
  }
53
}
54

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

67
export async function closeAllWorkers(): Promise<void> {
68
  await Promise.all(workers.map((w) => w.close()));
69
}