/** * Core Scheduled Jobs Framework * DO NOT MODIFY THIS FILE - You may break the project functionality * * This module provides the infrastructure for scheduled background jobs * using a dedicated Cloudflare Durable Object (SchedulerDO). * * SchedulerDO is a standalone Durable Object that: * - Owns its own storage for job metadata and history * - Handles alarm-based job scheduling * - Provides job management (pause, resume, trigger) * * Job handlers receive JobContext which includes env for entity access. */ import { DurableObject } from 'cloudflare:workers'; import { type Env } from './core-utils'; export interface ScheduledJob { /** Unique name for this job (kebab-case, e.g., "daily-cleanup") */ name: string; /** Cron expression (e.g., "0 0 * * *" for daily at midnight UTC) */ schedule: string; /** Human-readable description of what this job does */ description?: string; /** The handler function to execute */ handler: (ctx: JobContext) => Promise; /** Whether the job is enabled (default: true) */ enabled?: boolean; } export interface JobContext { /** Environment bindings */ env: Env; /** Name of the job being executed */ jobName: string; /** Unique ID for this execution run */ runId: string; /** When this job was scheduled to run */ scheduledAt: Date; /** Logger for structured job logging */ logger: JobLogger; } export interface JobResult { /** Whether the job completed successfully */ success: boolean; /** Additional result data (varies by job) */ [key: string]: unknown; } /** * Wire-safe schedule definition: what crosses the RPC boundary into * SchedulerDO. Deliberately excludes the handler function; over DO RPC a * function arrives as a callback stub, and invoking a stubbed handler * serializes JobContext back to the calling isolate, where env bindings (R2 * buckets, DO namespaces) cannot be serialized (AGENTCLI-6). Handlers are * bound inside the DO from its own isolate's module registry. */ export type ScheduledJobDefinition = Omit & Partial>; export interface JobLogger { info(message: string, data?: Record): void; warn(message: string, data?: Record): void; error(message: string, data?: Record): void; } export interface JobRunRecord { id: string; jobName: string; status: 'running' | 'completed' | 'failed'; scheduledAt: number; startedAt: number; completedAt?: number; result?: JobResult; error?: string; /** * Stack trace of the failure. Stored because the error MESSAGE alone made * the 2026-07 "Could not serialize object of type ..." production failures * undiagnosable: the message names the workerd serializer, not the framework * call site that hit it (AGENTCLI-6). */ errorStack?: string; } export interface ScheduleState { name: string; schedule: string; description?: string; enabled: boolean; lastRun: number | null; nextRun: number; lastError?: string; } export interface SchedulerRegistry { schedules: Record; initialized: boolean; } export interface ScheduleStatusResponse { schedules: Array<{ name: string; schedule: string; description?: string; enabled: boolean; lastRun: number | null; nextRun: number; status: 'active' | 'paused' | 'error'; lastError?: string; }>; } interface CronParts { minute: number[]; hour: number[]; dayOfMonth: number[]; month: number[]; dayOfWeek: number[]; } /** * Parse a cron expression into its component parts * Supports standard 5-field cron: minute hour day-of-month month day-of-week */ export declare function parseCronExpression(expr: string): CronParts; /** * Calculate the next run time for a cron expression after the given date */ export declare function calculateNextRun(cronExpression: string, after?: Date): Date; /** * SchedulerDO - Standalone Durable Object for job scheduling * * This is the actual Durable Object class that handles all scheduling. * It owns its own storage for job metadata and execution history. * * Job handlers receive env so they can access entities and other services. */ export declare class SchedulerDO extends DurableObject { private jobs; private initialized; constructor(ctx: DurableObjectState, env: Env); /** * Ensure the scheduler is initialized (lazy initialization for DO recovery) * This is needed because DOs can be evicted and recreated, losing in-memory state. * Also handles HMR: if getRegisteredSchedules() has changed since last init, re-sync. */ private ensureInitialized; /** * Alarm handler - processes scheduled jobs * Called by Cloudflare when an alarm fires */ alarm(): Promise; /** * Initialize the job scheduler with job definitions. * Can be called again after HMR to sync new/changed job definitions. */ initializeJobScheduler(jobs: ScheduledJobDefinition[]): Promise; /** * Handle alarm - execute due jobs */ private handleAlarm; /** * Execute a single job */ private executeJob; /** * Store a job execution record in history */ private storeHistoryRecord; /** * Schedule the next alarm for the earliest due job */ private scheduleNextAlarm; /** * Get status of all schedules */ getScheduleStatus(): Promise; /** * Get job execution history */ getJobHistory(jobName?: string, limit?: number): Promise; /** * Manually trigger a job (for testing/debugging) */ triggerJob(jobName: string): Promise; /** * Pause a scheduled job */ pauseJob(jobName: string): Promise; /** * Resume a paused job */ resumeJob(jobName: string): Promise; } /** * Initialize the job scheduler with the given jobs. */ export declare function initializeScheduler(env: Env, jobs: ScheduledJob[]): Promise; import type { Hono } from 'hono'; /** * Mount scheduler routes on the Hono app * Provides internal API for schedule management */ export declare function schedulerRoutes(app: Hono<{ Bindings: Env; }>): void; export {};