← back to Watches

analytics/scheduler.js

130 lines

/**
 * Analytics Report Scheduler
 * Automatically generates reports on schedule
 */

import cron from 'node-cron';
import ReportGenerator from './report-generator.js';

class AnalyticsScheduler {
  constructor(analyticsStore) {
    this.analyticsStore = analyticsStore;
    this.reportGenerator = new ReportGenerator(analyticsStore);
    this.jobs = [];
  }

  /**
   * Start all scheduled jobs
   */
  start() {
    console.log('Starting analytics scheduler...');

    // Daily report - every day at 2 AM
    const dailyJob = cron.schedule('0 2 * * *', async () => {
      console.log('Generating daily report...');
      try {
        await this.reportGenerator.generateDailyReport();
        console.log('Daily report generated successfully');
      } catch (error) {
        console.error('Failed to generate daily report:', error);
      }
    });

    this.jobs.push({ name: 'daily_report', job: dailyJob });

    // Weekly report - every Monday at 3 AM
    const weeklyJob = cron.schedule('0 3 * * 1', async () => {
      console.log('Generating weekly report...');
      try {
        await this.reportGenerator.generateWeeklyReport();
        console.log('Weekly report generated successfully');
      } catch (error) {
        console.error('Failed to generate weekly report:', error);
      }
    });

    this.jobs.push({ name: 'weekly_report', job: weeklyJob });

    // Monthly report - first day of month at 4 AM
    const monthlyJob = cron.schedule('0 4 1 * *', async () => {
      console.log('Generating monthly report...');
      try {
        await this.reportGenerator.generateMonthlyReport();
        console.log('Monthly report generated successfully');
      } catch (error) {
        console.error('Failed to generate monthly report:', error);
      }
    });

    this.jobs.push({ name: 'monthly_report', job: monthlyJob });

    // Hourly data backup - every hour
    const backupJob = cron.schedule('0 * * * *', () => {
      console.log('Backing up analytics data...');
      // Trigger backup in analytics-server.js
    });

    this.jobs.push({ name: 'hourly_backup', job: backupJob });

    console.log(`Analytics scheduler started with ${this.jobs.length} jobs`);
  }

  /**
   * Stop all scheduled jobs
   */
  stop() {
    console.log('Stopping analytics scheduler...');
    this.jobs.forEach(({ name, job }) => {
      job.stop();
      console.log(`Stopped job: ${name}`);
    });
    this.jobs = [];
  }

  /**
   * Manually trigger a report
   */
  async triggerReport(type) {
    console.log(`Manually triggering ${type} report...`);

    try {
      switch (type) {
        case 'daily':
          await this.reportGenerator.generateDailyReport();
          break;
        case 'weekly':
          await this.reportGenerator.generateWeeklyReport();
          break;
        case 'monthly':
          await this.reportGenerator.generateMonthlyReport();
          break;
        default:
          throw new Error(`Unknown report type: ${type}`);
      }

      console.log(`${type} report generated successfully`);
      return true;
    } catch (error) {
      console.error(`Failed to generate ${type} report:`, error);
      return false;
    }
  }

  /**
   * Get scheduler status
   */
  getStatus() {
    return {
      running: this.jobs.length > 0,
      jobs: this.jobs.map(({ name }) => name),
      nextRuns: this.jobs.map(({ name, job }) => ({
        name,
        // Cron jobs don't expose next run time easily, would need separate library
        status: 'scheduled'
      }))
    };
  }
}

export default AnalyticsScheduler;