eletrotupi / tcc/ api/src/lib/queue/WorkerRegistry.tsc377fb94289224023a0ab5d229329b5a4e06af51
2.3 KB | 73 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
import { logger } from "@app/lib/logger";
10

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

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

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

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

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

38
    logger.info({ queue: queueName }, "Worker booting...");
39
    const worker = new Worker(queueName, processor, {
40
      connection: {
41
        host: process.env.VALKEY_HOST,
42
        port: Number(process.env.VALKEY_PORT),
43
      },
44
      concurrency: concurrencyMap[queueName],
45
    } satisfies WorkerOptions);
46

47
    worker.on("failed", (job, err) => {
48
      logger.error({ err, queue: queueName, jobId: job?.id }, "job failed");
49
    });
50

51
    worker.on("error", (err) => {
52
      logger.error({ err, queue: queueName }, "worker error");
53
    });
54

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

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

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