64 lines
2.5 KiB
TypeScript
64 lines
2.5 KiB
TypeScript
|
|
import { getQueue, type QueueName } from './index';
|
||
|
|
import { logger } from '@/lib/logger';
|
||
|
|
|
||
|
|
interface RecurringJobDef {
|
||
|
|
queue: QueueName;
|
||
|
|
name: string;
|
||
|
|
pattern: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Register all recurring jobs from 11-REALTIME-AND-BACKGROUND-JOBS.md Section 3.2.
|
||
|
|
* Called once on server startup.
|
||
|
|
*/
|
||
|
|
export async function registerRecurringJobs(): Promise<void> {
|
||
|
|
const recurring: RecurringJobDef[] = [
|
||
|
|
// Documenso signature fallback poll — primary is webhooks, this is safety net
|
||
|
|
{ queue: 'documents', name: 'signature-poll', pattern: '0 */6 * * *' },
|
||
|
|
|
||
|
|
// Reminder checks
|
||
|
|
{ queue: 'notifications', name: 'reminder-check', pattern: '0 * * * *' },
|
||
|
|
{ queue: 'notifications', name: 'reminder-overdue-check', pattern: '*/15 * * * *' },
|
||
|
|
|
||
|
|
// Google Calendar background sync
|
||
|
|
{ queue: 'maintenance', name: 'calendar-sync', pattern: '*/30 * * * *' },
|
||
|
|
|
||
|
|
// Daily checks at 08:00
|
||
|
|
{ queue: 'notifications', name: 'invoice-overdue-check', pattern: '0 8 * * *' },
|
||
|
|
{ queue: 'notifications', name: 'tenure-expiry-check', pattern: '0 8 * * *' },
|
||
|
|
|
||
|
|
// Exchange rate refresh every 6 hours
|
||
|
|
{ queue: 'maintenance', name: 'currency-refresh', pattern: '0 */6 * * *' },
|
||
|
|
|
||
|
|
// Database backup / cleanup
|
||
|
|
{ queue: 'maintenance', name: 'database-backup', pattern: '0 2 * * *' },
|
||
|
|
{ queue: 'maintenance', name: 'backup-cleanup', pattern: '0 3 * * 0' }, // Sunday 03:00
|
||
|
|
|
||
|
|
// Session cleanup
|
||
|
|
{ queue: 'maintenance', name: 'session-cleanup', pattern: '0 4 * * *' },
|
||
|
|
|
||
|
|
// Report scheduler — checks every minute for reports due to run
|
||
|
|
{ queue: 'reports', name: 'report-scheduler', pattern: '* * * * *' },
|
||
|
|
|
||
|
|
// Notification digest — configurable per user; placeholder fires hourly
|
||
|
|
// TODO(L2): make per-user schedule configurable (read from user_settings)
|
||
|
|
{ queue: 'email', name: 'notification-digest', pattern: '0 * * * *' },
|
||
|
|
|
||
|
|
// Cleanup jobs
|
||
|
|
{ queue: 'maintenance', name: 'temp-file-cleanup', pattern: '0 5 * * *' },
|
||
|
|
{ queue: 'maintenance', name: 'form-expiry-check', pattern: '0 * * * *' },
|
||
|
|
];
|
||
|
|
|
||
|
|
for (const job of recurring) {
|
||
|
|
const queue = getQueue(job.queue);
|
||
|
|
await queue.upsertJobScheduler(
|
||
|
|
job.name,
|
||
|
|
{ pattern: job.pattern },
|
||
|
|
{ data: {}, name: job.name },
|
||
|
|
);
|
||
|
|
logger.info({ queue: job.queue, job: job.name, pattern: job.pattern }, 'Registered recurring job');
|
||
|
|
}
|
||
|
|
|
||
|
|
logger.info({ count: recurring.length }, 'All recurring jobs registered');
|
||
|
|
}
|