Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 1x 2x 2x 2x 2x 2x 2x 1x 1x 1x | import path from "node:path"; import type SQLite from "better-sqlite3"; import { type Queue, defineQueue as definePlainjobsQueue, defineWorker, } from "plainjobs"; import { getLogger } from "./log"; import { getManifest, getManifestOrThrow } from "./manifest"; export type Job<T> = { name: string; run: ({ data }: { data: T }) => Promise<void>; }; export function isJob<T>(job: unknown): job is Job<T> { return ( typeof job === "object" && job !== null && "run" in job && "name" in job && typeof job.run === "function" ); } export function defineJob<T>(opts: { name: string; run: ({ data }: { data: T }) => Promise<void>; }): Job<T> { return { name: path.parse(opts.name).name, run: opts.run, }; } export type Schedule = { name: string; cron: string; run: () => Promise<void>; }; export function isSchedule(schedule: unknown): schedule is Schedule { return ( typeof schedule === "object" && schedule !== null && "run" in schedule && "name" in schedule && typeof schedule.run === "function" ); } export function defineSchedule(opts: { name: string; cron: string; run: () => Promise<void>; }): Schedule { return { name: path.parse(opts.name).name, cron: opts.cron, run: opts.run, }; } export function defineQueue(opts: { connection: SQLite.Database; }): Queue { const logger = getLogger("queue"); return definePlainjobsQueue({ connection: opts.connection, logger }); } export async function work( queue: Queue, jobs: Record<string, Job<unknown>>, schedules: Record<string, Schedule>, ) { const log = getLogger("work"); if (!Object.values(jobs).length) log.warn("no jobs to run"); if (!Object.values(schedules).length) log.warn("no schedules to run"); for (const schedule of Object.values(schedules)) { log.info(`scheduling ${schedule.name} to run at ${schedule.cron}`); queue.schedule(schedule.name, { cron: schedule.cron }); } log.info(`starting worker for jobs: ${Object.keys(jobs).join(", ")}`); log.info( `starting worker for schedules: ${Object.keys(schedules).join(", ")}`, ); const workables = [...Object.values(jobs), ...Object.values(schedules)]; const workers = workables.map((w) => defineWorker(w.name, w.run, { queue, logger: log }), ); await Promise.all(workers.map((worker) => worker.start())); } export async function perform<T>(job: Job<T>, data?: T) { const log = getLogger("perform"); log.info(`performing job ${job.name}`); const { queue } = await getManifestOrThrow(["queue"]); queue.add(job.name, { data }); log.info(`job ${job.name} queued`); } |