Files
bodyshop-media-server/util/dailyS3Scheduler.ts
2025-11-06 15:15:32 -08:00

171 lines
4.5 KiB
TypeScript

import * as cron from "node-cron";
import { logger } from "../server.js";
import { S3Sync, createS3SyncFromEnv } from "./s3Sync.js";
export class DailyS3Scheduler {
private s3Sync: S3Sync | null = null;
private cronJob: cron.ScheduledTask | null = null;
constructor() {
this.s3Sync = createS3SyncFromEnv();
}
/**
* Start the daily S3 sync scheduler
* Runs at midnight PST (00:00 PST = 08:00 UTC during standard time, 07:00 UTC during daylight time)
*/
async start(): Promise<void> {
if (!this.s3Sync) {
logger.warn("S3 sync not configured. Skipping scheduler setup.");
return;
}
// Test S3 connection before starting scheduler
// const connectionTest = await this.s3Sync.testConnection();
// if (!connectionTest) {
// logger.error("S3 connection test failed. S3 sync scheduler will not be started.");
// return;
// }
// Cron expression for midnight PST
// Note: This uses PST timezone. During PDT (daylight time), it will still run at midnight local time
const cronExpression = "0 0 * * *"; // Every day at midnight
const timezone = "America/Los_Angeles"; // PST/PDT timezone
this.cronJob = cron.schedule(
cronExpression,
async () => {
//await this.performDailySync();
await this.triggerJobAnalysis();
},
{
timezone: timezone
}
);
logger.info(`Daily scheduler started. Will run at midnight PST/PDT.`);
logger.info(`Next sync scheduled for: ${this.getNextRunTime()}`);
}
/**
* Stop the scheduler
*/
stop(): void {
if (this.cronJob) {
this.cronJob.stop();
this.cronJob = null;
logger.info("Daily S3 sync scheduler stopped.");
}
}
/**
* Perform the daily sync operation
*/
private async performDailySync(): Promise<void> {
if (!this.s3Sync) {
logger.error("S3 sync not available for daily sync");
return;
}
const startTime = new Date();
logger.info(`Starting daily S3 sync at ${startTime.toISOString()}`);
try {
await this.s3Sync.syncJobsToS3();
const endTime = new Date();
const duration = endTime.getTime() - startTime.getTime();
logger.info(`Daily S3 sync completed successfully in ${duration}ms`);
} catch (error) {
logger.error("Daily S3 sync failed:", error);
}
}
/**
* Manually trigger a sync (useful for testing)
*/
async triggerManualSync(): Promise<void> {
if (!this.s3Sync) {
logger.error("S3 sync not configured");
return;
}
logger.info("Triggering manual S3 sync...");
await this.performDailySync();
}
async triggerJobAnalysis(): Promise<void> {
if (!this.s3Sync) {
logger.error("S3 sync not configured");
return;
}
logger.info("Triggering jobs directory analysis...");
try {
const analysis = await this.s3Sync.analyzeJobsDirectory();
logger.info("Jobs directory analysis completed:", analysis);
} catch (error) {
logger.error("Jobs directory analysis failed:", error);
}
}
/**
* Get the next scheduled run time
*/
private getNextRunTime(): string {
if (!this.cronJob) {
return "Not scheduled";
}
// Create a date object for midnight PST today
const now = new Date();
const pstNow = new Date(now.toLocaleString("en-US", { timeZone: "America/Los_Angeles" }));
// If it's past midnight today, next run is tomorrow at midnight
const nextRun = new Date(pstNow);
if (pstNow.getHours() > 0 || pstNow.getMinutes() > 0 || pstNow.getSeconds() > 0) {
nextRun.setDate(nextRun.getDate() + 1);
}
nextRun.setHours(0, 0, 0, 0);
return nextRun.toLocaleString("en-US", {
timeZone: "America/Los_Angeles",
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
timeZoneName: "short"
});
}
/**
* Get scheduler status
*/
async getStatus(): Promise<{
isConfigured: boolean;
isRunning: boolean;
nextRun: string;
syncStats?: { bucketName: string; region: string; keyPrefix: string; available: boolean };
}> {
let syncStats;
if (this.s3Sync) {
try {
syncStats = await this.s3Sync.getSyncStats();
} catch (error) {
logger.error("Failed to get sync stats:", error);
}
}
return {
isConfigured: this.s3Sync !== null,
isRunning: this.cronJob !== null,
nextRun: this.getNextRunTime(),
syncStats
};
}
}
// Export a singleton instance
export const dailyS3Scheduler = new DailyS3Scheduler();