Zuletzt aktiv 3 weeks ago

gistfile1.txt Originalformat
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 };