import { config } from '../config'; import { logger } from '../utils/logger'; import { getExpiredReportJobs, updateJobFields } from '../db/jobs'; import { deleteReportPdf } from '../db/storage'; import { insertJobEvent } from '../db/events'; /** * Periodic cleanup of expired PDF reports. * Runs every CLEANUP_INTERVAL minutes. * * Deletes report and Digital Receipt PDFs after their independent expiry time. * Deleted paths remain available in job events for the audit trail. */ export async function runCleanupReportsCron(): Promise { const cronLog = logger.child({ cron: 'cleanup-reports' }); cronLog.info('Starting report cleanup cron'); try { const expiredJobs = await getExpiredReportJobs(); if (expiredJobs.length === 0) { cronLog.info('No expired reports to clean up'); return; } cronLog.info(`Found ${expiredJobs.length} expired reports to clean up`); let deleted = 0; let failed = 0; for (const job of expiredJobs) { const now = Date.now(); if ( job.output_pdf_path && job.output_pdf_expires_at && new Date(job.output_pdf_expires_at).getTime() <= now ) { try { await deleteReportPdf(job.output_pdf_path); deleted++; await updateJobFields(job.id, { output_pdf_path: null }); await insertJobEvent({ job_id: job.id, identity_id: null, level: 'info', step: 'report_expired_deleted', message: `PDF report deleted after expiry: ${job.output_pdf_path}`, metadata: { expired_path: job.output_pdf_path }, }); cronLog.info(`Deleted expired report for job ${job.id}`); } catch (err) { failed++; cronLog.error(`Failed to delete report for job ${job.id}`, { error: err instanceof Error ? err.message : String(err), path: job.output_pdf_path, }); } } if ( job.receipt_pdf_path && job.receipt_pdf_expires_at && new Date(job.receipt_pdf_expires_at).getTime() <= now ) { try { await deleteReportPdf(job.receipt_pdf_path); deleted++; await updateJobFields(job.id, { receipt_pdf_path: null }); await insertJobEvent({ job_id: job.id, identity_id: null, level: 'info', step: 'receipt_expired_deleted', message: `Digital Receipt deleted after expiry: ${job.receipt_pdf_path}`, metadata: { expired_path: job.receipt_pdf_path }, }); cronLog.info(`Deleted expired Digital Receipt for job ${job.id}`); } catch (err) { failed++; cronLog.error(`Failed to delete Digital Receipt for job ${job.id}`, { error: err instanceof Error ? err.message : String(err), path: job.receipt_pdf_path, }); } } } cronLog.info('Report cleanup cron completed', { deleted, failed }); } catch (err) { cronLog.error('Report cleanup cron failed', { error: err instanceof Error ? err.message : String(err), }); } }