gistfile1.txt
· 3.0 KiB · Text
Brut
/**
* Scheduler — plugin-based cron job manager.
*
* Drop a file exporting `job: ScheduledJob` in this directory
* and it will be automatically scheduled.
*
* Slot-specific jobs (poll open/lock/close) are registered separately
* via Scheduler.scheduleSlots() since they depend on runtime config.
*/
import cron from "node-cron";
import { Client, TextChannel } from "discord.js";
import { ScheduledJob } from "./types";
import { Config } from "@systems/config";
import { TGSlot } from "@types";
// Import all jobs
import { job as weeklyReset } from "@scheduler/weekly-reset";
import { job as midnightCleanup } from "@scheduler/midnight-cleanup";
import { job as midnightSnapshot } from "@scheduler/midnight-snapshot";
const STATIC_JOBS: ScheduledJob[] = [
weeklyReset,
midnightCleanup,
midnightSnapshot
];
type PollCallback = (slot: TGSlot) => Promise<void>;
type LockCallback = (slot: TGSlot) => Promise<void>;
type CloseCallback = (slot: TGSlot) => Promise<void>;
let _tasks: cron.ScheduledTask[] = [];
function stopAll(): void {
_tasks.forEach((t) => t.stop());
_tasks = [];
}
export const Scheduler = {
/**
* Schedule all jobs — static crons + slot-based polls.
*/
schedule(
client: Client,
onPollOpen: PollCallback,
onPollLock: LockCallback,
onPollClose: CloseCallback,
): void {
stopAll();
const tz = process.env.TZ ?? "Etc/GMT-2";
const slots = Config.get({ section: "poll", key: "slots" }).filter((s) => s.active);
console.log(`[Scheduler] Weekly reset scheduled: "0 0 * * 1" in ${tz}`);
// Static jobs
for (const job of STATIC_JOBS) {
_tasks.push(cron.schedule(
job.cron,
() => job.run(client),
{ timezone: job.timezone ?? tz }
));
console.log(`[Scheduler] Registered: ${job.name} (${job.cron})`);
}
// Slot-based jobs
for (const slot of slots) {
const [openHour, openMin] = slot.pollOpens.split(":").map(Number);
_tasks.push(cron.schedule(
`${openMin} ${openHour} * * *`,
() => onPollOpen(slot),
{ timezone: tz }
));
_tasks.push(cron.schedule(
`0 ${slot.tgHour} * * *`,
() => onPollLock(slot),
{ timezone: tz }
));
const closeMinTotal = slot.tgHour * 60 + slot.closesAfter;
const closeHour = Math.floor(closeMinTotal / 60) % 24;
const closeMin = closeMinTotal % 60;
_tasks.push(cron.schedule(
`${closeMin} ${closeHour} * * *`,
() => onPollClose(slot),
{ timezone: tz }
));
}
console.log(`[Scheduler] ${STATIC_JOBS.length} static jobs + ${slots.length} slot(s) scheduled.`);
},
reschedule(
client: Client,
onPollOpen: PollCallback,
onPollLock: LockCallback,
onPollClose: CloseCallback,
): void {
Scheduler.schedule(client, onPollOpen, onPollLock, onPollClose);
},
stop(): void {
stopAll();
console.log(`[Scheduler] All jobs stopped.`);
},
};
| 1 | /** |
| 2 | * Scheduler — plugin-based cron job manager. |
| 3 | * |
| 4 | * Drop a file exporting `job: ScheduledJob` in this directory |
| 5 | * and it will be automatically scheduled. |
| 6 | * |
| 7 | * Slot-specific jobs (poll open/lock/close) are registered separately |
| 8 | * via Scheduler.scheduleSlots() since they depend on runtime config. |
| 9 | */ |
| 10 | |
| 11 | import cron from "node-cron"; |
| 12 | import { Client, TextChannel } from "discord.js"; |
| 13 | import { ScheduledJob } from "./types"; |
| 14 | import { Config } from "@systems/config"; |
| 15 | import { TGSlot } from "@types"; |
| 16 | |
| 17 | // Import all jobs |
| 18 | import { job as weeklyReset } from "@scheduler/weekly-reset"; |
| 19 | import { job as midnightCleanup } from "@scheduler/midnight-cleanup"; |
| 20 | import { job as midnightSnapshot } from "@scheduler/midnight-snapshot"; |
| 21 | |
| 22 | const STATIC_JOBS: ScheduledJob[] = [ |
| 23 | weeklyReset, |
| 24 | midnightCleanup, |
| 25 | midnightSnapshot |
| 26 | ]; |
| 27 | |
| 28 | type PollCallback = (slot: TGSlot) => Promise<void>; |
| 29 | type LockCallback = (slot: TGSlot) => Promise<void>; |
| 30 | type CloseCallback = (slot: TGSlot) => Promise<void>; |
| 31 | |
| 32 | let _tasks: cron.ScheduledTask[] = []; |
| 33 | |
| 34 | function stopAll(): void { |
| 35 | _tasks.forEach((t) => t.stop()); |
| 36 | _tasks = []; |
| 37 | } |
| 38 | |
| 39 | export const Scheduler = { |
| 40 | /** |
| 41 | * Schedule all jobs — static crons + slot-based polls. |
| 42 | */ |
| 43 | schedule( |
| 44 | client: Client, |
| 45 | onPollOpen: PollCallback, |
| 46 | onPollLock: LockCallback, |
| 47 | onPollClose: CloseCallback, |
| 48 | ): void { |
| 49 | stopAll(); |
| 50 | |
| 51 | const tz = process.env.TZ ?? "Etc/GMT-2"; |
| 52 | const slots = Config.get({ section: "poll", key: "slots" }).filter((s) => s.active); |
| 53 | |
| 54 | console.log(`[Scheduler] Weekly reset scheduled: "0 0 * * 1" in ${tz}`); |
| 55 | |
| 56 | // Static jobs |
| 57 | for (const job of STATIC_JOBS) { |
| 58 | _tasks.push(cron.schedule( |
| 59 | job.cron, |
| 60 | () => job.run(client), |
| 61 | { timezone: job.timezone ?? tz } |
| 62 | )); |
| 63 | console.log(`[Scheduler] Registered: ${job.name} (${job.cron})`); |
| 64 | } |
| 65 | |
| 66 | // Slot-based jobs |
| 67 | for (const slot of slots) { |
| 68 | const [openHour, openMin] = slot.pollOpens.split(":").map(Number); |
| 69 | |
| 70 | _tasks.push(cron.schedule( |
| 71 | `${openMin} ${openHour} * * *`, |
| 72 | () => onPollOpen(slot), |
| 73 | { timezone: tz } |
| 74 | )); |
| 75 | |
| 76 | _tasks.push(cron.schedule( |
| 77 | `0 ${slot.tgHour} * * *`, |
| 78 | () => onPollLock(slot), |
| 79 | { timezone: tz } |
| 80 | )); |
| 81 | |
| 82 | const closeMinTotal = slot.tgHour * 60 + slot.closesAfter; |
| 83 | const closeHour = Math.floor(closeMinTotal / 60) % 24; |
| 84 | const closeMin = closeMinTotal % 60; |
| 85 | _tasks.push(cron.schedule( |
| 86 | `${closeMin} ${closeHour} * * *`, |
| 87 | () => onPollClose(slot), |
| 88 | { timezone: tz } |
| 89 | )); |
| 90 | } |
| 91 | |
| 92 | console.log(`[Scheduler] ${STATIC_JOBS.length} static jobs + ${slots.length} slot(s) scheduled.`); |
| 93 | }, |
| 94 | |
| 95 | reschedule( |
| 96 | client: Client, |
| 97 | onPollOpen: PollCallback, |
| 98 | onPollLock: LockCallback, |
| 99 | onPollClose: CloseCallback, |
| 100 | ): void { |
| 101 | Scheduler.schedule(client, onPollOpen, onPollLock, onPollClose); |
| 102 | }, |
| 103 | |
| 104 | stop(): void { |
| 105 | stopAll(); |
| 106 | console.log(`[Scheduler] All jobs stopped.`); |
| 107 | }, |
| 108 | }; |