mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 05:05:38 -04:00
Add all 10 milestones: Drizzle ORM + SQLite database with WAL mode, Better Auth email/password authentication, TMDB API integration for search and metadata import, TV season/episode caching, user tracking (watchlist/status/watches/ratings with auto-transitions), discovery feeds (continue watching, library, recommendations), US streaming availability via TMDB providers, background job scheduler with instrumentation hook, and dark cinema-themed frontend with DM Serif Display + DM Sans typography and amber accent design system. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
62 lines
1.5 KiB
TypeScript
62 lines
1.5 KiB
TypeScript
interface Job {
|
|
name: string;
|
|
handler: () => Promise<void>;
|
|
intervalMs: number;
|
|
timer?: ReturnType<typeof setInterval>;
|
|
}
|
|
|
|
const globalForScheduler = globalThis as unknown as {
|
|
_scheduler: Scheduler | undefined;
|
|
};
|
|
|
|
class Scheduler {
|
|
private jobs = new Map<string, Job>();
|
|
private running = false;
|
|
|
|
register(name: string, handler: () => Promise<void>, intervalMs: number) {
|
|
this.jobs.set(name, { name, handler, intervalMs });
|
|
}
|
|
|
|
start() {
|
|
if (this.running) return;
|
|
this.running = true;
|
|
|
|
for (const job of this.jobs.values()) {
|
|
job.timer = setInterval(async () => {
|
|
try {
|
|
console.log(`[scheduler] Running job: ${job.name}`);
|
|
await job.handler();
|
|
console.log(`[scheduler] Completed job: ${job.name}`);
|
|
} catch (err) {
|
|
console.error(`[scheduler] Job ${job.name} failed:`, err);
|
|
}
|
|
}, job.intervalMs);
|
|
}
|
|
|
|
console.log(`[scheduler] Started ${this.jobs.size} jobs`);
|
|
}
|
|
|
|
stop() {
|
|
for (const job of this.jobs.values()) {
|
|
if (job.timer) clearInterval(job.timer);
|
|
}
|
|
this.running = false;
|
|
}
|
|
|
|
async runNow(name: string) {
|
|
const job = this.jobs.get(name);
|
|
if (!job) throw new Error(`Job not found: ${name}`);
|
|
await job.handler();
|
|
}
|
|
|
|
getJobNames() {
|
|
return [...this.jobs.keys()];
|
|
}
|
|
}
|
|
|
|
if (!globalForScheduler._scheduler) {
|
|
globalForScheduler._scheduler = new Scheduler();
|
|
}
|
|
|
|
export const scheduler = globalForScheduler._scheduler;
|