- Add job queue abstraction (InMemoryQueue and Redis/BullMQ adapter) - Add polling worker with retry logic and exponential backoff - Add 6 job handlers: darkwatch.scan, voiceprint.batch, hometitle.scan, removebrokers.process, reports.generate, notifications.send - Add cron-based scheduler with tier-appropriate frequencies (Basic/Plus/Premium) - Add tRPC scheduler router for admin (runJobNow, getJobStatus, etc.) - Add entry point with graceful shutdown support - Achieve 100% test pass rate for new job system
59 lines
1.7 KiB
TypeScript
59 lines
1.7 KiB
TypeScript
import { eq, and } from "drizzle-orm";
|
|
import { db } from "~/server/db";
|
|
import { reportSchedules } from "~/server/db/schema";
|
|
import { generateReport } from "~/server/services/reports.service";
|
|
|
|
interface ReportsGeneratePayload {
|
|
userId: string;
|
|
reportScheduleId?: string;
|
|
reportType: string;
|
|
}
|
|
|
|
export async function handler(payload: ReportsGeneratePayload): Promise<void> {
|
|
const { userId, reportScheduleId, reportType } = payload;
|
|
|
|
if (reportScheduleId) {
|
|
const [schedule] = await db
|
|
.select()
|
|
.from(reportSchedules)
|
|
.where(and(eq(reportSchedules.id, reportScheduleId), eq(reportSchedules.enabled, true)))
|
|
.limit(1);
|
|
|
|
if (!schedule) {
|
|
console.warn(`[reports.generate] Schedule ${reportScheduleId} not found or disabled`);
|
|
return;
|
|
}
|
|
|
|
await generateReport(userId, schedule.reportType as any, schedule.lastGeneratedAt?.toISOString());
|
|
} else {
|
|
await generateReport(userId, reportType as any);
|
|
}
|
|
|
|
if (reportScheduleId) {
|
|
await db
|
|
.update(reportSchedules)
|
|
.set({
|
|
lastGeneratedAt: new Date(),
|
|
nextScheduledAt: calculateNextRun(reportType),
|
|
updatedAt: new Date(),
|
|
})
|
|
.where(eq(reportSchedules.id, reportScheduleId));
|
|
}
|
|
|
|
console.log(`[reports.generate] Generated report for user ${userId}`);
|
|
}
|
|
|
|
function calculateNextRun(reportType: string): Date {
|
|
const now = new Date();
|
|
switch (reportType) {
|
|
case "WEEKLY_DIGEST":
|
|
return new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);
|
|
case "MONTHLY_PLUS":
|
|
return new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
|
|
case "ANNUAL_PREMIUM":
|
|
return new Date(now.getTime() + 365 * 24 * 60 * 60 * 1000);
|
|
default:
|
|
return new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
|
|
}
|
|
}
|