|
| 1 | +import CronParser from "cron-parser"; // Or your chosen cron library |
| 2 | +import { and, eq, lte } from "drizzle-orm"; |
| 3 | +import { drizzle } from "drizzle-orm/d1"; |
| 4 | + |
| 5 | +import { cronTriggers } from "./db/schema"; |
| 6 | + |
| 7 | +// This is a placeholder. You need to implement how workflows are triggered. |
| 8 | +// If executeWorkflow becomes more complex or used elsewhere, it could also be in its own file. |
| 9 | +async function executeWorkflow( |
| 10 | + workflowId: string, |
| 11 | + _env: any, |
| 12 | + _ctx: any |
| 13 | +): Promise<void> { |
| 14 | + console.log(`Executing workflow ${workflowId}`); |
| 15 | + // Example: await fetch(`https://your-service.com/api/execute-workflow/${workflowId}`, { method: 'POST' }); |
| 16 | + // Or: directly call a function if workflow logic is bundled |
| 17 | + // Remember to handle errors appropriately. |
| 18 | + await Promise.resolve(); // Replace with actual workflow execution logic |
| 19 | +} |
| 20 | + |
| 21 | +export async function handleCronTriggers( |
| 22 | + event: ScheduledEvent, |
| 23 | + env: { DB: D1Database }, |
| 24 | + ctx: ExecutionContext |
| 25 | +): Promise<void> { |
| 26 | + console.log(`Cron event triggered at: ${new Date(event.scheduledTime)}`); |
| 27 | + const db = drizzle(env.DB, { schema: { cronTriggers } }); |
| 28 | + |
| 29 | + const now = new Date(); |
| 30 | + |
| 31 | + try { |
| 32 | + const dueTriggers = await db |
| 33 | + .select() |
| 34 | + .from(cronTriggers) |
| 35 | + .where( |
| 36 | + and(eq(cronTriggers.active, true), lte(cronTriggers.nextRunAt, now)) |
| 37 | + ) |
| 38 | + .all(); |
| 39 | + |
| 40 | + if (dueTriggers.length === 0) { |
| 41 | + console.log("No due cron triggers found."); |
| 42 | + return; |
| 43 | + } |
| 44 | + |
| 45 | + console.log(`Found ${dueTriggers.length} due cron triggers.`); |
| 46 | + |
| 47 | + for (const trigger of dueTriggers) { |
| 48 | + console.log(`Processing trigger for workflow: ${trigger.workflowId}`); |
| 49 | + try { |
| 50 | + // 1. Execute the workflow |
| 51 | + await executeWorkflow(trigger.workflowId, env, ctx); |
| 52 | + |
| 53 | + // 2. Calculate next run time |
| 54 | + const interval = CronParser.parse(trigger.cronExpression, { |
| 55 | + currentDate: now, |
| 56 | + }); |
| 57 | + const nextRun = interval.next().toDate(); |
| 58 | + |
| 59 | + // 3. Update the trigger in the database |
| 60 | + await db |
| 61 | + .update(cronTriggers) |
| 62 | + .set({ |
| 63 | + lastRun: now, |
| 64 | + nextRunAt: nextRun, |
| 65 | + }) |
| 66 | + .where(eq(cronTriggers.workflowId, trigger.workflowId)) |
| 67 | + .execute(); |
| 68 | + |
| 69 | + console.log( |
| 70 | + `Workflow ${trigger.workflowId} executed. Next run at: ${nextRun.toISOString()}` |
| 71 | + ); |
| 72 | + } catch (err) { |
| 73 | + console.error( |
| 74 | + `Error processing trigger for workflow ${trigger.workflowId}:`, |
| 75 | + err |
| 76 | + ); |
| 77 | + // Optionally, you might want to implement retry logic or disable the trigger after too many failures. |
| 78 | + } |
| 79 | + } |
| 80 | + } catch (dbError) { |
| 81 | + console.error("Database error during scheduled task:", dbError); |
| 82 | + } |
| 83 | +} |
0 commit comments