@cloudnux/local-cloud-provider 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/schedule-plugin/plugin.ts","../../src/schedule-plugin/cron-utils.ts","../../src/schedule-plugin/utils.ts","../../src/schedule-plugin/core.ts","../../src/schedule-plugin/jobs.ts","../../src/schedule-plugin/persistence.ts","../../src/schedule-plugin/processing.ts","../../src/schedule-plugin/decorator.ts","../../src/schedule-plugin/routes.ts"],"sourcesContent":["import { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fsPlugin from \"fastify-plugin\";\n\nimport { SchedulerPluginOptions, SchedulerRuntime } from \"./types\";\nimport { DEFAULT_CONFIG, mergeConfig } from \"./core\";\nimport { tick } from \"./processing\";\nimport { initializePersistence } from \"./persistence\";\nimport { createSchedulerManager } from \"./decorator\";\nimport { registerSchedulerRoutes } from \"./routes\";\n\nexport const schedulerPlugin: FastifyPluginAsync<SchedulerPluginOptions> =\n fsPlugin(async (\n app: FastifyInstance,\n options: SchedulerPluginOptions\n ) => {\n const runtime: SchedulerRuntime = {\n config: mergeConfig(DEFAULT_CONFIG, options.config),\n schedulers: {},\n executions: {},\n executionHistory: [],\n isShuttingDown: false,\n runningExecutions: 0,\n isDirty: false,\n lastCleanupTime: Date.now(),\n lastSavedAt: Date.now(),\n lastRestartTime: new Date(),\n logging: app.logging,\n };\n\n // One timer for the entire plugin: every tickIntervalMs, run any job\n // that's due, then clean up old execution history / save persistence\n // once their own intervals have elapsed. See processing.ts:tick.\n const tickIntervalId = setInterval(() => tick(runtime), runtime.config.tickIntervalMs);\n app.addHook('onClose', async () => {\n runtime.isShuttingDown = true;\n clearInterval(tickIntervalId);\n });\n\n app.decorate('scheduler', createSchedulerManager(runtime));\n registerSchedulerRoutes(app, options.prefix);\n\n if (runtime.config.persistence.enabled) {\n await initializePersistence(runtime);\n }\n });\n","import { parseExpression } from 'cron-parser';\n\n/**\n * Professional cron parser using cron-parser library\n * \n * Installation:\n * npm install cron-parser\n * npm install -D @types/cron-parser\n */\n\ninterface CronParseOptions {\n preserveNaturalTiming?: boolean;\n timezone?: string;\n utc?: boolean;\n currentDate?: Date;\n endDate?: Date;\n iterator?: boolean;\n}\n\ninterface CronParseResult {\n nextRun: Date;\n isValid: boolean;\n error?: string;\n pattern?: string;\n description?: string;\n}\n\n/**\n * Parse cron expression and get next execution time\n */\nexport function parseCronExpression(\n cronExpression: string,\n lastRun?: Date,\n options: CronParseOptions = {}\n): CronParseResult {\n const {\n preserveNaturalTiming = true,\n timezone,\n utc = false,\n currentDate\n } = options;\n\n try {\n // Validate and normalize cron expression\n const normalizedCron = normalizeCronExpression(cronExpression);\n\n const parseOptions: any = {\n tz: timezone,\n utc: utc,\n currentDate: currentDate ?? new Date()\n };\n\n // Use lastRun for baseline if preserving natural timing\n if (preserveNaturalTiming && lastRun) {\n parseOptions.currentDate = lastRun;\n }\n\n const interval = parseExpression(normalizedCron, parseOptions);\n let nextRun = interval.next().toDate();\n\n // Ensure next run is in the future\n const now = new Date();\n while (nextRun <= now) {\n nextRun = interval.next().toDate();\n }\n\n return {\n nextRun,\n isValid: true,\n pattern: normalizedCron,\n description: describeCronExpression(normalizedCron)\n };\n\n } catch (error: any) {\n // Fallback to a safe default (every hour) - the caller gets the\n // failure via `isValid`/`error` on the returned result, so it can\n // log with whatever module context it has; this module has none.\n const fallbackTime = new Date();\n fallbackTime.setHours(fallbackTime.getHours() + 1);\n fallbackTime.setMinutes(0);\n fallbackTime.setSeconds(0);\n fallbackTime.setMilliseconds(0);\n\n return {\n nextRun: fallbackTime,\n isValid: false,\n error: error.message,\n pattern: cronExpression\n };\n }\n}\n\n/**\n * Get multiple next execution times\n */\nexport function getNextExecutions(\n cronExpression: string,\n count: number = 5,\n options: CronParseOptions = {}\n): Date[] {\n try {\n const normalizedCron = normalizeCronExpression(cronExpression);\n const parseOptions: any = {\n tz: options.timezone,\n utc: options.utc ?? false,\n currentDate: options.currentDate ?? new Date()\n };\n\n const interval = parseExpression(normalizedCron, parseOptions);\n const executions: Date[] = [];\n\n for (let i = 0; i < count; i++) {\n executions.push(interval.next().toDate());\n }\n\n return executions;\n } catch {\n return [];\n }\n}\n\n/**\n * Validate if a cron expression is valid\n */\nexport function validateCronExpression(cronExpression: string): boolean {\n try {\n const normalized = normalizeCronExpression(cronExpression);\n parseExpression(normalized);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Normalize cron expressions to handle different formats\n */\nfunction normalizeCronExpression(cronExpression: string): string {\n const parts = cronExpression.trim().split(/\\s+/);\n\n // Handle different cron formats\n if (parts.length === 5) {\n // Standard 5-field format: minute hour day month dayOfWeek\n return cronExpression;\n } else if (parts.length === 6) {\n // 6-field format with seconds: second minute hour day month dayOfWeek\n return cronExpression;\n } else if (parts.length === 7) {\n // 7-field format with year: second minute hour day month dayOfWeek year\n return cronExpression;\n } else {\n throw new Error(`Invalid cron format: expected 5, 6, or 7 fields, got ${parts.length}`);\n }\n}\n\n/**\n * Provide human-readable description of cron expression\n */\nfunction describeCronExpression(cronExpression: string): string {\n const parts = cronExpression.split(' ');\n\n // Handle common patterns\n const patterns: Record<string, string> = {\n '*/5 * * * *': 'Every 5 minutes',\n '0 * * * *': 'Every hour at minute 0',\n '0 */2 * * *': 'Every 2 hours',\n '0 0 * * *': 'Daily at midnight',\n '0 6 * * *': 'Daily at 6:00 AM',\n '0 0 * * 0': 'Weekly on Sunday at midnight',\n '0 0 1 * *': 'Monthly on the 1st at midnight',\n '0 0 1 1 *': 'Yearly on January 1st at midnight'\n };\n\n if (patterns[cronExpression]) {\n return patterns[cronExpression];\n }\n\n // Basic description for other patterns\n if (parts.length >= 5) {\n const [minute, hour, day, month, dayOfWeek] = parts;\n\n let description = 'Runs ';\n\n if (minute.includes('*/')) {\n const interval = minute.split('*/')[1];\n description += `every ${interval} minutes`;\n } else if (minute === '*') {\n description += 'every minute';\n } else {\n description += `at minute ${minute}`;\n }\n\n if (hour.includes('*/')) {\n const interval = hour.split('*/')[1];\n description += `, every ${interval} hours`;\n } else if (hour !== '*') {\n description += `, at hour ${hour}`;\n }\n\n if (day !== '*') {\n description += `, on day ${day}`;\n }\n\n if (month !== '*') {\n description += `, in month ${month}`;\n }\n\n if (dayOfWeek !== '*') {\n const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n const dayNames = dayOfWeek.split(',').map(d => days[parseInt(d)] || d).join(', ');\n description += `, on ${dayNames}`;\n }\n\n return description;\n }\n\n return 'Custom schedule';\n}\n\n/**\n * Calculate time until next execution\n */\nexport function timeUntilNextExecution(cronExpression: string, timezone?: string): number {\n const result = parseCronExpression(cronExpression, undefined, { timezone });\n if (!result.isValid) {\n return -1;\n }\n\n return result.nextRun.getTime() - Date.now();\n}\n\n/**\n * Check if a time matches a cron expression\n */\nexport function doesTimeMatchCron(cronExpression: string, date: Date, timezone?: string): boolean {\n try {\n const normalizedCron = normalizeCronExpression(cronExpression);\n const parseOptions: any = {\n tz: timezone,\n currentDate: date\n };\n\n const interval = parseExpression(normalizedCron, parseOptions);\n const nextExecution = interval.next().toDate();\n\n // Check if the date is very close to the next execution (within 1 minute)\n const timeDiff = Math.abs(nextExecution.getTime() - date.getTime());\n return timeDiff < 60000; // 1 minute tolerance\n } catch {\n return false;\n }\n}\n\n/**\n * Detect the type of scheduling expression\n */\nexport function detectExpressionType(expression: string | undefined): 'cron' | 'rate' | 'unknown' {\n if (!expression || typeof expression !== 'string') {\n return 'unknown';\n }\n const trimmedExpression = expression.trim();\n\n // Check for AWS rate expression pattern\n // Format: \"rate(value unit)\" where unit can be minute(s), hour(s), day(s)\n const ratePattern = /^rate\\(\\s*(\\d+)\\s+(minute|minutes|hour|hours|day|days)\\s*\\)$/i;\n if (ratePattern.test(trimmedExpression)) {\n return 'rate';\n }\n\n // Check for cron expression pattern\n // Should have 5, 6, or 7 space-separated fields\n const cronParts = trimmedExpression.split(/\\s+/);\n if (cronParts.length >= 5 && cronParts.length <= 7) {\n // Additional validation: check if parts contain valid cron characters\n const cronCharPattern = /^[\\d\\*\\-\\,\\/\\?\\#LW]+$/;\n const validCronParts = cronParts.every(part => cronCharPattern.test(part) || part === '*');\n\n if (validCronParts) {\n return 'cron';\n }\n }\n\n return 'unknown';\n}\n\n/**\n * Convert AWS rate expression to cron expression\n * \n * AWS Rate expressions format: rate(value unit)\n * Examples:\n * - rate(5 minutes) -> *\\/5 * * * *\n * - rate(1 hour) -> 0 * * * *\n * - rate(2 hours) -> 0 *\\/2 * * *\n * - rate(1 day) -> 0 0 * * *\n * - rate(7 days) -> 0 0 *\\/7 * *\n*/\nexport function convertRateToCron(rateExpression: string): {\n cronExpression: string;\n isValid: boolean;\n error?: string;\n originalRate: string;\n description: string;\n} {\n const trimmedExpression = rateExpression.trim();\n\n // Parse rate expression\n const ratePattern = /^rate\\(\\s*(\\d+)\\s+(minute|minutes|hour|hours|day|days)\\s*\\)$/i;\n const match = trimmedExpression.match(ratePattern);\n\n if (!match) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Invalid rate expression format. Expected: rate(value unit)',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n const value = parseInt(match[1]);\n const unit = match[2].toLowerCase();\n\n // Validate value\n if (value <= 0) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Rate value must be greater than 0',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n let cronExpression = '';\n let description = '';\n\n try {\n switch (unit) {\n case 'minute':\n case 'minutes':\n if (value > 59) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Minutes value cannot exceed 59. Use hours for longer intervals.',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n if (value === 1) {\n cronExpression = '* * * * *';\n description = 'Every minute';\n } else {\n cronExpression = `*/${value} * * * *`;\n description = `Every ${value} minutes`;\n }\n break;\n\n case 'hour':\n case 'hours':\n if (value > 23) {\n // For hours > 23, convert to days if evenly divisible by 24\n if (value % 24 === 0) {\n const days = value / 24;\n cronExpression = `0 0 */${days} * *`;\n description = `Every ${days} day${days > 1 ? 's' : ''}`;\n } else {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Hours value greater than 23 must be divisible by 24, or use days unit.',\n originalRate: rateExpression,\n description: ''\n };\n }\n } else if (value === 1) {\n cronExpression = '0 * * * *';\n description = 'Every hour';\n } else {\n cronExpression = `0 */${value} * * *`;\n description = `Every ${value} hours`;\n }\n break;\n\n case 'day':\n case 'days':\n if (value > 365) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Days value cannot exceed 365',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n if (value === 1) {\n cronExpression = '0 0 * * *';\n description = 'Every day (daily)';\n } else if (value === 7) {\n cronExpression = '0 0 * * 0';\n description = 'Every 7 days (weekly)';\n } else if (value <= 31) {\n cronExpression = `0 0 */${value} * *`;\n description = `Every ${value} days`;\n } else {\n // For large day intervals, we need to be more careful\n // This is an approximation since months have different lengths\n cronExpression = `0 0 */${value} * *`;\n description = `Every ${value} days (approximate)`;\n }\n break;\n\n default:\n return {\n cronExpression: '',\n isValid: false,\n error: `Unsupported time unit: ${unit}. Use minute(s), hour(s), or day(s).`,\n originalRate: rateExpression,\n description: ''\n };\n }\n\n // Validate the generated cron expression\n if (!validateCronExpression(cronExpression)) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Generated cron expression is invalid',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n return {\n cronExpression,\n isValid: true,\n originalRate: rateExpression,\n description\n };\n\n } catch (error: any) {\n return {\n cronExpression: '',\n isValid: false,\n error: `Conversion error: ${error.message}`,\n originalRate: rateExpression,\n description: ''\n };\n }\n}","import { ScheduledJob, SchedulerConfig } from \"./types\";\nimport { parseCronExpression } from \"./cron-utils\";\n\nexport const generateJobId = (): string =>\n `job_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\nexport const generateExecutionId = (): string =>\n `exec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\nexport const calculateNextRun = (\n job: ScheduledJob,\n preserveNaturalTiming: boolean = true\n): Date => {\n const now = new Date();\n\n if (job.cronExpression) {\n const result = parseCronExpression(job.cronExpression, job.lastRun, {\n preserveNaturalTiming,\n timezone: job.timezone,\n currentDate: preserveNaturalTiming && job.lastRun ? job.lastRun : now\n });\n return result.nextRun;\n }\n\n if (job.intervalMs) {\n return new Date(now.getTime() + job.intervalMs);\n }\n\n if (job.delayMs) {\n return new Date(now.getTime() + job.delayMs);\n }\n\n // Default: 1 hour\n return new Date(now.getTime() + 3600000);\n};\n\nexport const calculateNextRunFromLastRun = (\n job: ScheduledJob,\n lastRun: Date | undefined,\n config: SchedulerConfig\n): Date => {\n const now = new Date();\n\n if (job.cronExpression) {\n const result = parseCronExpression(job.cronExpression, lastRun, {\n preserveNaturalTiming: config.restartBehavior.preserveNaturalTiming,\n timezone: job.timezone ?? config.cron.defaultTimezone\n });\n return result.nextRun;\n }\n\n if (job.intervalMs && lastRun) {\n let nextRun = new Date(lastRun.getTime() + job.intervalMs);\n\n if (config.restartBehavior.skipMissedRuns) {\n while (nextRun <= now) {\n nextRun = new Date(nextRun.getTime() + job.intervalMs);\n }\n } else {\n if (nextRun <= now) {\n nextRun = new Date(now.getTime() + job.intervalMs);\n }\n }\n\n return nextRun;\n }\n\n return calculateNextRun(job, config.restartBehavior.preserveNaturalTiming);\n};\n\nexport const hasJobDefinitionChanged = (currentJob: ScheduledJob, savedJob: any): boolean => (\n currentJob.cronExpression !== savedJob.cronExpression ||\n currentJob.intervalMs !== savedJob.intervalMs ||\n currentJob.delayMs !== savedJob.delayMs ||\n currentJob.maxRuns !== savedJob.maxRuns ||\n currentJob.timezone !== savedJob.timezone\n);\n\nexport const shouldSkipJob = (job: ScheduledJob): boolean => {\n if (!job.enabled) return true;\n if (job.maxRuns && job.runCount >= job.maxRuns) return true;\n return false;\n};\n\nexport const isJobReadyToRun = (job: ScheduledJob): boolean => {\n const now = new Date();\n return job.nextRun.getTime() <= now.getTime();\n};\n\nexport const getTimeUntilNextRun = (job: ScheduledJob): number =>\n Math.max(0, job.nextRun.getTime() - Date.now());","import { SchedulerConfig, SchedulerDashboardJob, SchedulerRuntime } from \"./types\";\nimport { getNextExecutions, parseCronExpression } from \"./cron-utils\";\nimport { getTimeUntilNextRun } from \"./utils\";\n\n// default config\nexport const DEFAULT_CONFIG: SchedulerConfig = {\n tickIntervalMs: 1000,\n persistence: {\n enabled: true,\n directory: './.develop/scheduler-data',\n saveInterval: 30000, // 30 seconds\n saveOnShutdown: false,\n },\n execution: {\n maxConcurrent: 5,\n defaultTimeout: 300000, // 5 minutes\n },\n cleanup: {\n maxExecutionHistory: 1000,\n cleanupInterval: 600000, // 10 minutes\n },\n restartBehavior: {\n preserveNaturalTiming: true,\n skipMissedRuns: true,\n maxTimingDrift: 60000, // 1 minute\n rapidRestartThreshold: 10000, // 10 seconds\n },\n cron: {\n defaultTimezone: undefined, // Use system timezone\n logCronDetails: true,\n },\n};\n\n// Pure function to merge configs\nexport const mergeConfig = (defaultConfig: SchedulerConfig, userConfig?: Partial<SchedulerConfig>): SchedulerConfig => ({\n ...defaultConfig,\n ...userConfig,\n persistence: { ...defaultConfig.persistence, ...userConfig?.persistence },\n execution: { ...defaultConfig.execution, ...userConfig?.execution },\n cleanup: { ...defaultConfig.cleanup, ...userConfig?.cleanup },\n restartBehavior: { ...defaultConfig.restartBehavior, ...userConfig?.restartBehavior },\n cron: { ...defaultConfig.cron, ...userConfig?.cron },\n});\n\n// Pure function to build the dashboard view of every job\nexport const createDashboardSummary = (runtime: SchedulerRuntime): { jobs: SchedulerDashboardJob[]; runningExecutions: number } => {\n const jobs = Object.values(runtime.schedulers).map((scheduler): SchedulerDashboardJob => {\n const upcomingExecutions = scheduler.job.cronExpression\n ? getNextExecutions(scheduler.job.cronExpression, 3, { timezone: scheduler.job.timezone })\n : [];\n\n const cronDescription = scheduler.job.cronExpression\n ? parseCronExpression(scheduler.job.cronExpression, undefined, { timezone: scheduler.job.timezone }).description\n : undefined;\n\n return {\n ...scheduler.job,\n isRunning: scheduler.isRunning,\n timeUntilNextRun: getTimeUntilNextRun(scheduler.job),\n upcomingExecutions,\n cronDescription,\n };\n });\n\n return { jobs, runningExecutions: runtime.runningExecutions };\n};\n\n// Pure function to build the executions view\nexport const createExecutionsSummary = (runtime: SchedulerRuntime) => ({\n executions: runtime.executionHistory.slice(-50), // Last 50 executions\n running: Object.values(runtime.executions).filter(e => e.status === 'running'),\n});\n","import { JobDefinition, JobExecution, JobHandler, ScheduledJob, SchedulerConfig, SchedulerService } from \"./types\";\nimport { detectExpressionType, convertRateToCron } from \"./cron-utils\";\nimport { generateExecutionId, generateJobId, calculateNextRun, calculateNextRunFromLastRun } from \"./utils\";\n\n// Pure function to validate a job definition before it's turned into a job.\n// A job needs exactly one timing source; only validate the cron expression\n// itself when one was actually given (intervalMs/delayMs-only jobs have no\n// cron expression to check).\nexport const validateJobDefinition = (jobDef: JobDefinition): void => {\n if (!jobDef.cronExpression && !jobDef.intervalMs && !jobDef.delayMs) {\n throw new Error(`Job ${jobDef.name} must specify a cronExpression, intervalMs, or delayMs`);\n }\n\n if (jobDef.cronExpression && detectExpressionType(jobDef.cronExpression) === \"unknown\") {\n throw new Error(`Invalid cron expression for job: ${jobDef.name}`);\n }\n};\n\n// Pure function to turn a job definition into a scheduled job\nexport const createJobFromDefinition = (jobDef: JobDefinition, config: SchedulerConfig): ScheduledJob => {\n validateJobDefinition(jobDef);\n\n const expressionType = detectExpressionType(jobDef.cronExpression);\n const cronExpression = expressionType === \"rate\"\n ? convertRateToCron(jobDef.cronExpression!).cronExpression\n : jobDef.cronExpression;\n\n const job: ScheduledJob = {\n id: generateJobId(),\n name: jobDef.name,\n cronExpression,\n intervalMs: jobDef.intervalMs,\n delayMs: jobDef.delayMs,\n nextRun: new Date(),\n enabled: jobDef.enabled ?? true,\n runCount: 0,\n maxRuns: jobDef.maxRuns,\n metadata: jobDef.metadata,\n createdAt: new Date(),\n timezone: jobDef.timezone,\n module: jobDef.module,\n };\n\n job.nextRun = calculateNextRun(job, config.restartBehavior.preserveNaturalTiming);\n return job;\n};\n\n// Pure function to create a scheduler service for a job\nexport const createSchedulerService = (job: ScheduledJob, handler: JobHandler): SchedulerService => ({\n job,\n handler,\n isRunning: false,\n});\n\n// Pure function to create a job execution record\nexport const createJobExecution = (jobId: string): JobExecution => ({\n id: generateExecutionId(),\n jobId,\n startTime: new Date(),\n status: 'running',\n});\n\n// Pure function to mark an execution as finished\nexport const completeExecution = (\n execution: JobExecution,\n result?: any,\n error?: string\n): JobExecution => ({\n ...execution,\n endTime: new Date(),\n status: error ? 'failed' : 'completed',\n result,\n error,\n});\n\n// Pure function to advance a job's run count/timing after an execution\nexport const updateJobAfterExecution = (\n job: ScheduledJob,\n execution: JobExecution,\n config: SchedulerConfig\n): ScheduledJob => {\n const updatedJob: ScheduledJob = {\n ...job,\n lastRun: execution.startTime,\n runCount: job.runCount + 1,\n };\n\n if (updatedJob.enabled) {\n updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, updatedJob.lastRun, config);\n }\n\n return updatedJob;\n};\n\n// Pure function to enable a job and recompute its next run\nexport const enableJob = (scheduler: SchedulerService): SchedulerService => ({\n ...scheduler,\n job: {\n ...scheduler.job,\n enabled: true,\n nextRun: calculateNextRun(scheduler.job),\n },\n});\n\n// Pure function to disable a job\nexport const disableJob = (scheduler: SchedulerService): SchedulerService => ({\n ...scheduler,\n job: { ...scheduler.job, enabled: false },\n});\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\n\nimport { JobExecution, ScheduledJob, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { hasJobDefinitionChanged, calculateNextRunFromLastRun } from \"./utils\";\nimport { parseCronExpression } from \"./cron-utils\";\n\ninterface SchedulerStateData {\n jobs: ScheduledJob[];\n executions: JobExecution[];\n savedAt: Date;\n version: string;\n}\n\nconst stateFilePath = (directory: string): string => path.join(directory, 'scheduler-state.json');\n\nconst tempFilePath = (directory: string): string => path.join(directory, `scheduler-state.${Date.now()}.temp.json`);\n\nconst restoreExecutionHistory = (savedExecutions: JobExecution[]): JobExecution[] =>\n savedExecutions.map((exec) => ({\n ...exec,\n startTime: new Date(exec.startTime),\n endTime: exec.endTime ? new Date(exec.endTime) : undefined,\n }));\n\nconst readStateData = async (directory: string): Promise<SchedulerStateData | null> => {\n const data = await fs.readFile(stateFilePath(directory), 'utf8');\n return JSON.parse(data);\n};\n\nexport const saveSchedulerState = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n const stateData: SchedulerStateData = {\n jobs: Object.values(runtime.schedulers).map(s => s.job),\n executions: runtime.executionHistory.slice(-100),\n savedAt: new Date(),\n version: '1.0',\n };\n\n const file = stateFilePath(runtime.config.persistence.directory);\n const temp = tempFilePath(runtime.config.persistence.directory);\n\n // Write to a temp file first, then rename - rename is atomic, so a\n // reader never sees a half-written file.\n await fs.writeFile(temp, JSON.stringify(stateData, null, 2), 'utf8');\n await fs.rename(temp, file);\n\n runtime.logging.debug('Scheduler state saved');\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, 'Failed to save scheduler state');\n }\n};\n\n// Recalculates - or preserves - a restored job's nextRun depending on how\n// long ago the process restarted, so a quick redeploy doesn't lose timing\n// but a long outage doesn't fire a pile of catch-up runs.\nconst validateAndAdjustNextRun = (\n job: ScheduledJob,\n savedNextRun: Date | undefined,\n runtime: SchedulerRuntime\n): Date => {\n const { config, lastRestartTime, logging } = runtime;\n const now = new Date();\n\n if (!savedNextRun || savedNextRun <= now) {\n logging.debug({ module: job.module }, `Saved next run is in the past for ${job.name} - recalculating`);\n return calculateNextRunFromLastRun(job, job.lastRun, config);\n }\n\n const isRapidRestart = now.getTime() - lastRestartTime.getTime() < config.restartBehavior.rapidRestartThreshold;\n if (isRapidRestart) {\n logging.debug({ module: job.module }, `Rapid restart detected for ${job.name} - preserving saved timing`);\n return savedNextRun;\n }\n\n if (job.cronExpression || job.intervalMs) {\n const expectedNextRun = calculateNextRunFromLastRun(job, job.lastRun, config);\n const drift = Math.abs(savedNextRun.getTime() - expectedNextRun.getTime());\n if (drift > config.restartBehavior.maxTimingDrift) {\n logging.debug({ module: job.module }, `Adjusting timing for ${job.name} - drift of ${Math.round(drift / 1000)}s detected`);\n return expectedNextRun;\n }\n }\n\n return savedNextRun;\n};\n\n// Restores this job's saved run history (count, lastRun) and next-run\n// timing from the persisted state file. Mirrors queue-plugin's per-queue\n// loadQueueState: called from addJob right after the scheduler is\n// registered, not at plugin init - the saved file has nothing to match\n// against that early, since no jobs have been added yet.\nexport const loadJobState = async (runtime: SchedulerRuntime, scheduler: SchedulerService): Promise<SchedulerService> => {\n try {\n const stateData = await readStateData(runtime.config.persistence.directory);\n if (!stateData) {\n return scheduler;\n }\n\n const savedJob = stateData.jobs.find(job => job.name === scheduler.job.name);\n if (!savedJob) {\n return scheduler;\n }\n\n const definitionChanged = hasJobDefinitionChanged(scheduler.job, savedJob);\n const lastRun = savedJob.lastRun ? new Date(savedJob.lastRun) : undefined;\n\n const updatedJob: ScheduledJob = {\n ...scheduler.job,\n runCount: savedJob.runCount,\n lastRun,\n };\n\n if (definitionChanged) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job definition changed: ${savedJob.name} - recalculating schedule`);\n updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, lastRun, runtime.config);\n } else {\n updatedJob.nextRun = validateAndAdjustNextRun(updatedJob, savedJob.nextRun ? new Date(savedJob.nextRun) : undefined, runtime);\n }\n\n if (runtime.config.cron.logCronDetails && updatedJob.cronExpression) {\n const result = parseCronExpression(updatedJob.cronExpression, updatedJob.lastRun, { timezone: updatedJob.timezone });\n runtime.logging.debug(\n { module: scheduler.job.module },\n `Job restored: ${savedJob.name} - ${result.description} - next: ${updatedJob.nextRun.toLocaleString()}`\n );\n } else {\n runtime.logging.debug({ module: scheduler.job.module }, `Job state restored: ${savedJob.name}`);\n }\n\n return { ...scheduler, job: updatedJob };\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n runtime.logging.debug('No saved scheduler state found - starting fresh');\n } else {\n runtime.logging.error({ error: error?.message }, `Failed to load job state for ${scheduler.job.name}`);\n }\n return scheduler;\n }\n};\n\n// Execution history isn't tied to any one job, so it's restored once at\n// plugin init (unlike per-job state, which loadJobState restores lazily as\n// each job is registered).\nexport const loadExecutionHistory = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n const stateData = await readStateData(runtime.config.persistence.directory);\n if (stateData?.executions) {\n runtime.executionHistory = restoreExecutionHistory(stateData.executions);\n }\n } catch (error: any) {\n if (error.code !== 'ENOENT') {\n runtime.logging.error({ error: error?.message }, 'Failed to load execution history');\n }\n }\n};\n\nexport const initializePersistence = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n await fs.mkdir(runtime.config.persistence.directory, { recursive: true });\n await loadExecutionHistory(runtime);\n\n if (runtime.config.persistence.saveOnShutdown) {\n const shutdownHandler = async () => {\n runtime.logging.debug('Saving scheduler state before shutdown...');\n await saveSchedulerState(runtime);\n process.exit(0);\n };\n\n process.on('SIGINT', shutdownHandler);\n process.on('SIGTERM', shutdownHandler);\n }\n\n runtime.logging.debug(`Scheduler persistence initialized: ${runtime.config.persistence.directory}`);\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, 'Failed to initialize scheduler persistence');\n }\n};\n","import { JobExecution, JobHandler, ScheduledJob, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { completeExecution, createJobExecution, updateJobAfterExecution } from \"./jobs\";\nimport { isJobReadyToRun, shouldSkipJob } from \"./utils\";\nimport { saveSchedulerState } from \"./persistence\";\n\n// Pure function to check whether a job can run right now\nexport const canExecuteJob = (\n runtime: SchedulerRuntime,\n scheduler: SchedulerService\n): { canExecute: boolean; reason?: string } => {\n if (runtime.isShuttingDown) {\n return { canExecute: false, reason: 'System is shutting down' };\n }\n\n if (scheduler.isRunning) {\n return { canExecute: false, reason: 'Job is already running' };\n }\n\n if (shouldSkipJob(scheduler.job)) {\n const reason = !scheduler.job.enabled ? 'Job is disabled' : 'Job reached maximum runs';\n return { canExecute: false, reason };\n }\n\n if (runtime.runningExecutions >= runtime.config.execution.maxConcurrent) {\n return { canExecute: false, reason: 'Maximum concurrent executions reached' };\n }\n\n return { canExecute: true };\n};\n\nconst executeJobWithTimeout = async (\n handler: JobHandler,\n job: ScheduledJob,\n execution: JobExecution,\n timeoutMs: number\n): Promise<any> => {\n let timerId: NodeJS.Timeout;\n\n try {\n return await Promise.race([\n handler(job, execution),\n new Promise((_, reject) => {\n timerId = setTimeout(() => reject(new Error('Job execution timeout')), timeoutMs);\n }),\n ]);\n } finally {\n clearTimeout(timerId!);\n }\n};\n\n// Runs one job through its handler, recording the execution and advancing\n// its nextRun. Used by both the tick (once per due job) and triggerJob -\n// both go through the same path, wrapped in runWithLogContext by the\n// caller so every log call below carries the job's module/reqId.\nexport const executeJob = async (runtime: SchedulerRuntime, scheduler: SchedulerService): Promise<void> => {\n const execution = createJobExecution(scheduler.job.id);\n // Tracked in two places (the `executions` map and `executionHistory`)\n // but as a single shared reference - completeExecution below mutates\n // this same object via Object.assign so both views stay in sync,\n // instead of completeExecution's return value only updating one of them.\n runtime.executions[execution.id] = execution;\n runtime.executionHistory.push(execution);\n scheduler.isRunning = true;\n runtime.runningExecutions++;\n\n runtime.logging.info(`Executing job ${scheduler.job.name} (${execution.id})`);\n\n try {\n const result = await executeJobWithTimeout(\n scheduler.handler,\n scheduler.job,\n execution,\n runtime.config.execution.defaultTimeout\n );\n\n Object.assign(execution, completeExecution(execution, result));\n\n const duration = execution.endTime!.getTime() - execution.startTime.getTime();\n runtime.logging.debug(`Job completed in ${duration}ms`);\n } catch (error: any) {\n Object.assign(execution, completeExecution(execution, undefined, error.message));\n runtime.logging.error(`Job failed ${scheduler.job.name}: ${error.message}`);\n } finally {\n scheduler.isRunning = false;\n runtime.runningExecutions--;\n scheduler.job = updateJobAfterExecution(scheduler.job, execution, runtime.config);\n\n if (scheduler.job.maxRuns && scheduler.job.runCount >= scheduler.job.maxRuns) {\n runtime.logging.info(`Job ${scheduler.job.name} reached max runs (${scheduler.job.maxRuns})`);\n }\n\n if (runtime.config.persistence.enabled) {\n runtime.isDirty = true;\n }\n }\n};\n\nconst dispatchJobIfDue = (runtime: SchedulerRuntime, scheduler: SchedulerService): void => {\n if (!scheduler.job.enabled || !isJobReadyToRun(scheduler.job)) {\n return;\n }\n\n const { canExecute, reason } = canExecuteJob(runtime, scheduler);\n if (!canExecute) {\n // Not a permanent skip (except the maxRuns case, logged once above\n // instead) - e.g. at max concurrency, or another tick of the same\n // job already running. The job's nextRun hasn't moved, so the very\n // next tick simply tries again, instead of the old per-job timer\n // needing to be explicitly rescheduled with a delay. Logged at\n // debug to avoid spamming at tick frequency.\n if (reason === 'Maximum concurrent executions reached') {\n runtime.logging.debug({ module: scheduler.job.module }, `Delaying job ${scheduler.job.name} - ${reason}`);\n }\n return;\n }\n\n runtime.logging.runWithLogContext(\n { module: scheduler.job.module, reqId: scheduler.job.id },\n () => executeJob(runtime, scheduler)\n );\n};\n\nexport const cleanupExecutionHistory = (runtime: SchedulerRuntime): void => {\n const { maxExecutionHistory } = runtime.config.cleanup;\n if (runtime.executionHistory.length <= maxExecutionHistory) {\n return;\n }\n\n const removed = runtime.executionHistory.splice(0, runtime.executionHistory.length - maxExecutionHistory);\n runtime.logging.debug(`Cleaned up ${removed.length} old execution records`);\n};\n\nconst maybeCleanup = (runtime: SchedulerRuntime, now: number): void => {\n if (now - runtime.lastCleanupTime < runtime.config.cleanup.cleanupInterval) {\n return;\n }\n runtime.lastCleanupTime = now;\n cleanupExecutionHistory(runtime);\n};\n\nconst maybeSavePersistence = (runtime: SchedulerRuntime, now: number): void => {\n if (!runtime.config.persistence.enabled || !runtime.isDirty) {\n return;\n }\n\n const saveInterval = runtime.config.persistence.saveInterval ?? 0;\n if (saveInterval > 0 && now - runtime.lastSavedAt >= saveInterval) {\n runtime.lastSavedAt = now;\n runtime.isDirty = false;\n saveSchedulerState(runtime);\n }\n};\n\n// The one timer for the whole plugin. Every tickIntervalMs: run any job\n// whose nextRun has arrived (this is also how a manual triggerJob's\n// recurrence shows up - nothing schedules its own setTimeout anymore); then\n// clean up old execution history and save persistence if their intervals\n// have elapsed.\nexport const tick = (runtime: SchedulerRuntime): void => {\n const now = Date.now();\n for (const scheduler of Object.values(runtime.schedulers)) {\n dispatchJobIfDue(runtime, scheduler);\n }\n maybeCleanup(runtime, now);\n maybeSavePersistence(runtime, now);\n};\n","import { JobDefinition, JobHandler, SchedulerManager, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { createJobFromDefinition, createSchedulerService, disableJob as disableJobData, enableJob as enableJobData } from \"./jobs\";\nimport { createDashboardSummary, createExecutionsSummary } from \"./core\";\nimport { getNextExecutions, parseCronExpression } from \"./cron-utils\";\nimport { loadJobState } from \"./persistence\";\nimport { executeJob } from \"./processing\";\n\nconst isValidJobName = (jobName: string): boolean => {\n return typeof jobName === 'string' && jobName.length > 0 && /^[a-zA-Z0-9_-]+$/.test(jobName);\n};\n\nconst validateJobName = (jobName: string): void => {\n if (!jobName || typeof jobName !== 'string') {\n throw new Error('Job name must be a non-empty string');\n }\n\n if (!isValidJobName(jobName)) {\n throw new Error('Job name must contain only alphanumeric characters, hyphens, and underscores');\n }\n};\n\nconst validateHandler = (handler: JobHandler): void => {\n if (typeof handler !== 'function') {\n throw new Error('Handler must be a function');\n }\n};\n\nconst findSchedulerByName = (runtime: SchedulerRuntime, jobName: string): SchedulerService | undefined =>\n Object.values(runtime.schedulers).find(scheduler => scheduler.job.name === jobName);\n\nexport const addJob = async (runtime: SchedulerRuntime, jobDefinition: JobDefinition): Promise<string> => {\n try {\n validateJobName(jobDefinition.name);\n validateHandler(jobDefinition.handler);\n\n const existing = findSchedulerByName(runtime, jobDefinition.name);\n if (existing) {\n runtime.logging.warn({ module: jobDefinition.module }, `Job already exists: ${jobDefinition.name}.`);\n return existing.job.id;\n }\n\n const job = createJobFromDefinition(jobDefinition, runtime.config);\n\n if (runtime.config.cron.logCronDetails && job.cronExpression) {\n const timezone = job.timezone ?? runtime.config.cron.defaultTimezone;\n const result = parseCronExpression(job.cronExpression, undefined, { timezone });\n runtime.logging.debug(\n { module: jobDefinition.module },\n `Job ${jobDefinition.name}: ${result.description} - Next: ${result.nextRun.toLocaleString()}`\n );\n\n const upcoming = getNextExecutions(job.cronExpression, 3, { timezone });\n runtime.logging.debug(\n { module: jobDefinition.module },\n `Upcoming: ${upcoming.map(d => d.toLocaleTimeString()).join(', ')}`\n );\n }\n\n let scheduler = createSchedulerService(job, jobDefinition.handler);\n\n if (runtime.config.persistence.enabled) {\n scheduler = await loadJobState(runtime, scheduler);\n }\n\n runtime.schedulers[scheduler.job.id] = scheduler;\n\n runtime.logging.info({ module: jobDefinition.module }, `Job added: ${jobDefinition.name} (${scheduler.job.id})`);\n\n return scheduler.job.id;\n } catch (error: any) {\n runtime.logging.error({ module: jobDefinition.module, error: error.message }, `Failed to add job ${jobDefinition.name}`);\n throw error;\n }\n};\n\nexport const removeJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.isRunning) {\n runtime.logging.warn({ module: scheduler.job.module }, `Removing job that is currently running: ${jobName}`);\n }\n\n delete runtime.schedulers[scheduler.job.id];\n\n runtime.logging.info({ module: scheduler.job.module }, `Job removed: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to remove job ${jobName}`);\n throw error;\n }\n};\n\nexport const hasJob = (runtime: SchedulerRuntime, jobName: string): boolean => {\n try {\n validateJobName(jobName);\n return !!findSchedulerByName(runtime, jobName);\n } catch {\n return false;\n }\n};\n\nexport const listJobs = (runtime: SchedulerRuntime, module?: string): string[] => {\n return Object.values(runtime.schedulers)\n .filter(scheduler => !module || scheduler.job.module === module)\n .map(scheduler => scheduler.job.name)\n .sort();\n};\n\nexport const getJobStats = (runtime: SchedulerRuntime, jobName: string): SchedulerService | null => {\n try {\n validateJobName(jobName);\n return findSchedulerByName(runtime, jobName) ?? null;\n } catch {\n return null;\n }\n};\n\nexport const getJobsMap = (runtime: SchedulerRuntime): Record<string, SchedulerService> => {\n // Return a copy to prevent external modification\n return { ...runtime.schedulers };\n};\n\nexport const enableJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.job.enabled) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job is already enabled: ${jobName}`);\n return;\n }\n\n runtime.schedulers[scheduler.job.id] = enableJobData(scheduler);\n runtime.logging.info({ module: scheduler.job.module }, `Job enabled: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to enable job ${jobName}`);\n throw error;\n }\n};\n\nexport const disableJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (!scheduler.job.enabled) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job is already disabled: ${jobName}`);\n return;\n }\n\n runtime.schedulers[scheduler.job.id] = disableJobData(scheduler);\n runtime.logging.info({ module: scheduler.job.module }, `Job disabled: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to disable job ${jobName}`);\n throw error;\n }\n};\n\nexport const triggerJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.isRunning) {\n throw new Error(`Job '${jobName}' is already running`);\n }\n\n runtime.logging.info({ module: scheduler.job.module }, `Job triggered: ${jobName}`);\n\n // Fire-and-forget, same as the tick's own dispatch - callers (e.g.\n // the trigger route) get an immediate response rather than waiting\n // out the job's full run.\n runtime.logging.runWithLogContext(\n { module: scheduler.job.module, reqId: scheduler.job.id },\n () => executeJob(runtime, scheduler)\n );\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to trigger job ${jobName}`);\n throw error;\n }\n};\n\nexport const getDashboardSummary = (runtime: SchedulerRuntime) => createDashboardSummary(runtime);\n\nexport const getExecutionsSummary = (runtime: SchedulerRuntime) => createExecutionsSummary(runtime);\n\n// Unlike getExecutionsSummary (last 50 across every job), this filters the\n// full executionHistory down to one job first - so a busy job elsewhere\n// can't push a quieter job's own runs out of view.\nexport const getJobExecutionHistory = (runtime: SchedulerRuntime, jobName: string, limit = 50) => {\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n return [];\n }\n\n return runtime.executionHistory\n .filter(execution => execution.jobId === scheduler.job.id)\n .slice(-limit)\n .reverse();\n};\n\n// The one place runtime gets bound into the public app.scheduler shape -\n// Fastify needs a plain object of methods with no runtime param, so this\n// wraps each plain function above with `runtime` pre-applied. Everything\n// above this line is a normal function you can call directly with an\n// explicit runtime, e.g. in tests.\nexport const createSchedulerManager = (runtime: SchedulerRuntime): SchedulerManager => ({\n addJob: (jobDefinition) => addJob(runtime, jobDefinition),\n removeJob: (jobName) => removeJob(runtime, jobName),\n hasJob: (jobName) => hasJob(runtime, jobName),\n listJobs: (module) => listJobs(runtime, module),\n getJobStats: (jobName) => getJobStats(runtime, jobName),\n getJobsMap: () => getJobsMap(runtime),\n getConfig: () => runtime.config,\n enableJob: (jobName) => enableJob(runtime, jobName),\n disableJob: (jobName) => disableJob(runtime, jobName),\n triggerJob: (jobName) => triggerJob(runtime, jobName),\n getDashboardSummary: () => getDashboardSummary(runtime),\n getExecutionsSummary: () => getExecutionsSummary(runtime),\n getJobExecutionHistory: (jobName, limit) => getJobExecutionHistory(runtime, jobName, limit),\n});\n","import { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\n\n// Function to register all routes\nexport const registerSchedulerRoutes = (\n app: FastifyInstance,\n prefix: string = \"schedule\"\n): void => {\n app.get(`/${prefix}/dashboard`,\n async (_: FastifyRequest, reply: FastifyReply) => {\n return reply.status(200).send(app.scheduler.getDashboardSummary());\n });\n\n app.get(`/${prefix}/executions`,\n async (_: FastifyRequest, reply: FastifyReply) => {\n return reply.status(200).send(app.scheduler.getExecutionsSummary());\n });\n\n app.post<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/trigger`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.triggerJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job triggered successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n\n app.put<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/enable`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.enableJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job enabled successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n\n app.put<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/disable`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.disableJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job disabled successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n};\n"],"mappings":"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","names":["enableJob","disableJob"]}
1
+ {"version":3,"sources":["../../src/schedule-plugin/plugin.ts","../../src/schedule-plugin/cron-utils.ts","../../src/schedule-plugin/utils.ts","../../src/schedule-plugin/core.ts","../../src/schedule-plugin/jobs.ts","../../src/schedule-plugin/persistence.ts","../../src/schedule-plugin/processing.ts","../../src/schedule-plugin/decorator.ts","../../src/schedule-plugin/routes.ts"],"sourcesContent":["import { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fsPlugin from \"fastify-plugin\";\n\nimport { SchedulerPluginOptions, SchedulerRuntime } from \"./types\";\nimport { DEFAULT_CONFIG, mergeConfig } from \"./core\";\nimport { tick } from \"./processing\";\nimport { initializePersistence } from \"./persistence\";\nimport { createSchedulerManager } from \"./decorator\";\nimport { registerSchedulerRoutes } from \"./routes\";\n\nexport const schedulerPlugin: FastifyPluginAsync<SchedulerPluginOptions> =\n fsPlugin(async (\n app: FastifyInstance,\n options: SchedulerPluginOptions\n ) => {\n const runtime: SchedulerRuntime = {\n config: mergeConfig(DEFAULT_CONFIG, options.config),\n schedulers: {},\n executions: {},\n executionHistory: [],\n isShuttingDown: false,\n runningExecutions: 0,\n isDirty: false,\n lastCleanupTime: Date.now(),\n lastSavedAt: Date.now(),\n lastRestartTime: new Date(),\n logging: app.logging,\n };\n\n // One timer for the entire plugin: every tickIntervalMs, run any job\n // that's due, then clean up old execution history / save persistence\n // once their own intervals have elapsed. See processing.ts:tick.\n const tickIntervalId = setInterval(() => tick(runtime), runtime.config.tickIntervalMs);\n app.addHook('onClose', async () => {\n runtime.isShuttingDown = true;\n clearInterval(tickIntervalId);\n });\n\n app.decorate('scheduler', createSchedulerManager(runtime));\n registerSchedulerRoutes(app, options.prefix);\n\n if (runtime.config.persistence.enabled) {\n await initializePersistence(runtime);\n }\n });\n","import { parseExpression } from 'cron-parser';\n\n/**\n * Professional cron parser using cron-parser library\n * \n * Installation:\n * npm install cron-parser\n * npm install -D @types/cron-parser\n */\n\ninterface CronParseOptions {\n preserveNaturalTiming?: boolean;\n timezone?: string;\n utc?: boolean;\n currentDate?: Date;\n endDate?: Date;\n iterator?: boolean;\n}\n\ninterface CronParseResult {\n nextRun: Date;\n isValid: boolean;\n error?: string;\n pattern?: string;\n description?: string;\n}\n\n/**\n * Parse cron expression and get next execution time\n */\nexport function parseCronExpression(\n cronExpression: string,\n lastRun?: Date,\n options: CronParseOptions = {}\n): CronParseResult {\n const {\n preserveNaturalTiming = true,\n timezone,\n utc = false,\n currentDate\n } = options;\n\n try {\n // Validate and normalize cron expression\n const normalizedCron = normalizeCronExpression(cronExpression);\n\n const parseOptions: any = {\n tz: timezone,\n utc: utc,\n currentDate: currentDate ?? new Date()\n };\n\n // Use lastRun for baseline if preserving natural timing\n if (preserveNaturalTiming && lastRun) {\n parseOptions.currentDate = lastRun;\n }\n\n const interval = parseExpression(normalizedCron, parseOptions);\n let nextRun = interval.next().toDate();\n\n // Ensure next run is in the future\n const now = new Date();\n while (nextRun <= now) {\n nextRun = interval.next().toDate();\n }\n\n return {\n nextRun,\n isValid: true,\n pattern: normalizedCron,\n description: describeCronExpression(normalizedCron)\n };\n\n } catch (error: any) {\n // Fallback to a safe default (every hour) - the caller gets the\n // failure via `isValid`/`error` on the returned result, so it can\n // log with whatever module context it has; this module has none.\n const fallbackTime = new Date();\n fallbackTime.setHours(fallbackTime.getHours() + 1);\n fallbackTime.setMinutes(0);\n fallbackTime.setSeconds(0);\n fallbackTime.setMilliseconds(0);\n\n return {\n nextRun: fallbackTime,\n isValid: false,\n error: error.message,\n pattern: cronExpression\n };\n }\n}\n\n/**\n * Get multiple next execution times\n */\nexport function getNextExecutions(\n cronExpression: string,\n count: number = 5,\n options: CronParseOptions = {}\n): Date[] {\n try {\n const normalizedCron = normalizeCronExpression(cronExpression);\n const parseOptions: any = {\n tz: options.timezone,\n utc: options.utc ?? false,\n currentDate: options.currentDate ?? new Date()\n };\n\n const interval = parseExpression(normalizedCron, parseOptions);\n const executions: Date[] = [];\n\n for (let i = 0; i < count; i++) {\n executions.push(interval.next().toDate());\n }\n\n return executions;\n } catch {\n return [];\n }\n}\n\n/**\n * Validate if a cron expression is valid\n */\nexport function validateCronExpression(cronExpression: string): boolean {\n try {\n const normalized = normalizeCronExpression(cronExpression);\n parseExpression(normalized);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Normalize cron expressions to handle different formats\n */\nfunction normalizeCronExpression(cronExpression: string): string {\n const parts = cronExpression.trim().split(/\\s+/);\n\n // Handle different cron formats\n if (parts.length === 5) {\n // Standard 5-field format: minute hour day month dayOfWeek\n return cronExpression;\n } else if (parts.length === 6) {\n // 6-field format with seconds: second minute hour day month dayOfWeek\n return cronExpression;\n } else if (parts.length === 7) {\n // 7-field format with year: second minute hour day month dayOfWeek year\n return cronExpression;\n } else {\n throw new Error(`Invalid cron format: expected 5, 6, or 7 fields, got ${parts.length}`);\n }\n}\n\n/**\n * Provide human-readable description of cron expression\n */\nfunction describeCronExpression(cronExpression: string): string {\n const parts = cronExpression.split(' ');\n\n // Handle common patterns\n const patterns: Record<string, string> = {\n '*/5 * * * *': 'Every 5 minutes',\n '0 * * * *': 'Every hour at minute 0',\n '0 */2 * * *': 'Every 2 hours',\n '0 0 * * *': 'Daily at midnight',\n '0 6 * * *': 'Daily at 6:00 AM',\n '0 0 * * 0': 'Weekly on Sunday at midnight',\n '0 0 1 * *': 'Monthly on the 1st at midnight',\n '0 0 1 1 *': 'Yearly on January 1st at midnight'\n };\n\n if (patterns[cronExpression]) {\n return patterns[cronExpression];\n }\n\n // Basic description for other patterns\n if (parts.length >= 5) {\n const [minute, hour, day, month, dayOfWeek] = parts;\n\n let description = 'Runs ';\n\n if (minute.includes('*/')) {\n const interval = minute.split('*/')[1];\n description += `every ${interval} minutes`;\n } else if (minute === '*') {\n description += 'every minute';\n } else {\n description += `at minute ${minute}`;\n }\n\n if (hour.includes('*/')) {\n const interval = hour.split('*/')[1];\n description += `, every ${interval} hours`;\n } else if (hour !== '*') {\n description += `, at hour ${hour}`;\n }\n\n if (day !== '*') {\n description += `, on day ${day}`;\n }\n\n if (month !== '*') {\n description += `, in month ${month}`;\n }\n\n if (dayOfWeek !== '*') {\n const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n const dayNames = dayOfWeek.split(',').map(d => days[parseInt(d)] || d).join(', ');\n description += `, on ${dayNames}`;\n }\n\n return description;\n }\n\n return 'Custom schedule';\n}\n\n/**\n * Calculate time until next execution\n */\nexport function timeUntilNextExecution(cronExpression: string, timezone?: string): number {\n const result = parseCronExpression(cronExpression, undefined, { timezone });\n if (!result.isValid) {\n return -1;\n }\n\n return result.nextRun.getTime() - Date.now();\n}\n\n/**\n * Check if a time matches a cron expression\n */\nexport function doesTimeMatchCron(cronExpression: string, date: Date, timezone?: string): boolean {\n try {\n const normalizedCron = normalizeCronExpression(cronExpression);\n const parseOptions: any = {\n tz: timezone,\n currentDate: date\n };\n\n const interval = parseExpression(normalizedCron, parseOptions);\n const nextExecution = interval.next().toDate();\n\n // Check if the date is very close to the next execution (within 1 minute)\n const timeDiff = Math.abs(nextExecution.getTime() - date.getTime());\n return timeDiff < 60000; // 1 minute tolerance\n } catch {\n return false;\n }\n}\n\n/**\n * Detect the type of scheduling expression\n */\nexport function detectExpressionType(expression: string | undefined): 'cron' | 'rate' | 'unknown' {\n if (!expression || typeof expression !== 'string') {\n return 'unknown';\n }\n const trimmedExpression = expression.trim();\n\n // Check for AWS rate expression pattern\n // Format: \"rate(value unit)\" where unit can be minute(s), hour(s), day(s)\n const ratePattern = /^rate\\(\\s*(\\d+)\\s+(minute|minutes|hour|hours|day|days)\\s*\\)$/i;\n if (ratePattern.test(trimmedExpression)) {\n return 'rate';\n }\n\n // Check for cron expression pattern\n // Should have 5, 6, or 7 space-separated fields\n const cronParts = trimmedExpression.split(/\\s+/);\n if (cronParts.length >= 5 && cronParts.length <= 7) {\n // Additional validation: check if parts contain valid cron characters\n const cronCharPattern = /^[\\d\\*\\-\\,\\/\\?\\#LW]+$/;\n const validCronParts = cronParts.every(part => cronCharPattern.test(part) || part === '*');\n\n if (validCronParts) {\n return 'cron';\n }\n }\n\n return 'unknown';\n}\n\n/**\n * Convert AWS rate expression to cron expression\n * \n * AWS Rate expressions format: rate(value unit)\n * Examples:\n * - rate(5 minutes) -> *\\/5 * * * *\n * - rate(1 hour) -> 0 * * * *\n * - rate(2 hours) -> 0 *\\/2 * * *\n * - rate(1 day) -> 0 0 * * *\n * - rate(7 days) -> 0 0 *\\/7 * *\n*/\nexport function convertRateToCron(rateExpression: string): {\n cronExpression: string;\n isValid: boolean;\n error?: string;\n originalRate: string;\n description: string;\n} {\n const trimmedExpression = rateExpression.trim();\n\n // Parse rate expression\n const ratePattern = /^rate\\(\\s*(\\d+)\\s+(minute|minutes|hour|hours|day|days)\\s*\\)$/i;\n const match = trimmedExpression.match(ratePattern);\n\n if (!match) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Invalid rate expression format. Expected: rate(value unit)',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n const value = parseInt(match[1]);\n const unit = match[2].toLowerCase();\n\n // Validate value\n if (value <= 0) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Rate value must be greater than 0',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n let cronExpression = '';\n let description = '';\n\n try {\n switch (unit) {\n case 'minute':\n case 'minutes':\n if (value > 59) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Minutes value cannot exceed 59. Use hours for longer intervals.',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n if (value === 1) {\n cronExpression = '* * * * *';\n description = 'Every minute';\n } else {\n cronExpression = `*/${value} * * * *`;\n description = `Every ${value} minutes`;\n }\n break;\n\n case 'hour':\n case 'hours':\n if (value > 23) {\n // For hours > 23, convert to days if evenly divisible by 24\n if (value % 24 === 0) {\n const days = value / 24;\n cronExpression = `0 0 */${days} * *`;\n description = `Every ${days} day${days > 1 ? 's' : ''}`;\n } else {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Hours value greater than 23 must be divisible by 24, or use days unit.',\n originalRate: rateExpression,\n description: ''\n };\n }\n } else if (value === 1) {\n cronExpression = '0 * * * *';\n description = 'Every hour';\n } else {\n cronExpression = `0 */${value} * * *`;\n description = `Every ${value} hours`;\n }\n break;\n\n case 'day':\n case 'days':\n if (value > 365) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Days value cannot exceed 365',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n if (value === 1) {\n cronExpression = '0 0 * * *';\n description = 'Every day (daily)';\n } else if (value === 7) {\n cronExpression = '0 0 * * 0';\n description = 'Every 7 days (weekly)';\n } else if (value <= 31) {\n cronExpression = `0 0 */${value} * *`;\n description = `Every ${value} days`;\n } else {\n // For large day intervals, we need to be more careful\n // This is an approximation since months have different lengths\n cronExpression = `0 0 */${value} * *`;\n description = `Every ${value} days (approximate)`;\n }\n break;\n\n default:\n return {\n cronExpression: '',\n isValid: false,\n error: `Unsupported time unit: ${unit}. Use minute(s), hour(s), or day(s).`,\n originalRate: rateExpression,\n description: ''\n };\n }\n\n // Validate the generated cron expression\n if (!validateCronExpression(cronExpression)) {\n return {\n cronExpression: '',\n isValid: false,\n error: 'Generated cron expression is invalid',\n originalRate: rateExpression,\n description: ''\n };\n }\n\n return {\n cronExpression,\n isValid: true,\n originalRate: rateExpression,\n description\n };\n\n } catch (error: any) {\n return {\n cronExpression: '',\n isValid: false,\n error: `Conversion error: ${error.message}`,\n originalRate: rateExpression,\n description: ''\n };\n }\n}","import { ScheduledJob, SchedulerConfig } from \"./types\";\nimport { parseCronExpression } from \"./cron-utils\";\n\nexport const generateJobId = (): string =>\n `job_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\nexport const generateExecutionId = (): string =>\n `exec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n\nexport const calculateNextRun = (\n job: ScheduledJob,\n preserveNaturalTiming: boolean = true\n): Date => {\n const now = new Date();\n\n if (job.cronExpression) {\n const result = parseCronExpression(job.cronExpression, job.lastRun, {\n preserveNaturalTiming,\n timezone: job.timezone,\n currentDate: preserveNaturalTiming && job.lastRun ? job.lastRun : now\n });\n return result.nextRun;\n }\n\n if (job.intervalMs) {\n return new Date(now.getTime() + job.intervalMs);\n }\n\n if (job.delayMs) {\n return new Date(now.getTime() + job.delayMs);\n }\n\n // Default: 1 hour\n return new Date(now.getTime() + 3600000);\n};\n\nexport const calculateNextRunFromLastRun = (\n job: ScheduledJob,\n lastRun: Date | undefined,\n config: SchedulerConfig\n): Date => {\n const now = new Date();\n\n if (job.cronExpression) {\n const result = parseCronExpression(job.cronExpression, lastRun, {\n preserveNaturalTiming: config.restartBehavior.preserveNaturalTiming,\n timezone: job.timezone ?? config.cron.defaultTimezone\n });\n return result.nextRun;\n }\n\n if (job.intervalMs && lastRun) {\n let nextRun = new Date(lastRun.getTime() + job.intervalMs);\n\n if (config.restartBehavior.skipMissedRuns) {\n while (nextRun <= now) {\n nextRun = new Date(nextRun.getTime() + job.intervalMs);\n }\n } else {\n if (nextRun <= now) {\n nextRun = new Date(now.getTime() + job.intervalMs);\n }\n }\n\n return nextRun;\n }\n\n return calculateNextRun(job, config.restartBehavior.preserveNaturalTiming);\n};\n\nexport const hasJobDefinitionChanged = (currentJob: ScheduledJob, savedJob: any): boolean => (\n currentJob.cronExpression !== savedJob.cronExpression ||\n currentJob.intervalMs !== savedJob.intervalMs ||\n currentJob.delayMs !== savedJob.delayMs ||\n currentJob.maxRuns !== savedJob.maxRuns ||\n currentJob.timezone !== savedJob.timezone\n);\n\nexport const shouldSkipJob = (job: ScheduledJob): boolean => {\n if (!job.enabled) return true;\n if (job.maxRuns && job.runCount >= job.maxRuns) return true;\n return false;\n};\n\nexport const isJobReadyToRun = (job: ScheduledJob): boolean => {\n const now = new Date();\n return job.nextRun.getTime() <= now.getTime();\n};\n\nexport const getTimeUntilNextRun = (job: ScheduledJob): number =>\n Math.max(0, job.nextRun.getTime() - Date.now());","import { SchedulerConfig, SchedulerDashboardJob, SchedulerRuntime } from \"./types\";\nimport { getNextExecutions, parseCronExpression } from \"./cron-utils\";\nimport { getTimeUntilNextRun } from \"./utils\";\n\n// default config\nexport const DEFAULT_CONFIG: SchedulerConfig = {\n tickIntervalMs: 1000,\n persistence: {\n enabled: true,\n directory: './.develop/.scheduler-data',\n saveInterval: 30000, // 30 seconds\n saveOnShutdown: false,\n },\n execution: {\n maxConcurrent: 5,\n defaultTimeout: 300000, // 5 minutes\n },\n cleanup: {\n maxExecutionHistory: 1000,\n cleanupInterval: 600000, // 10 minutes\n },\n restartBehavior: {\n preserveNaturalTiming: true,\n skipMissedRuns: true,\n maxTimingDrift: 60000, // 1 minute\n rapidRestartThreshold: 10000, // 10 seconds\n },\n cron: {\n defaultTimezone: undefined, // Use system timezone\n logCronDetails: true,\n },\n};\n\n// Pure function to merge configs\nexport const mergeConfig = (defaultConfig: SchedulerConfig, userConfig?: Partial<SchedulerConfig>): SchedulerConfig => ({\n ...defaultConfig,\n ...userConfig,\n persistence: { ...defaultConfig.persistence, ...userConfig?.persistence },\n execution: { ...defaultConfig.execution, ...userConfig?.execution },\n cleanup: { ...defaultConfig.cleanup, ...userConfig?.cleanup },\n restartBehavior: { ...defaultConfig.restartBehavior, ...userConfig?.restartBehavior },\n cron: { ...defaultConfig.cron, ...userConfig?.cron },\n});\n\n// Pure function to build the dashboard view of every job\nexport const createDashboardSummary = (runtime: SchedulerRuntime): { jobs: SchedulerDashboardJob[]; runningExecutions: number } => {\n const jobs = Object.values(runtime.schedulers).map((scheduler): SchedulerDashboardJob => {\n const upcomingExecutions = scheduler.job.cronExpression\n ? getNextExecutions(scheduler.job.cronExpression, 3, { timezone: scheduler.job.timezone })\n : [];\n\n const cronDescription = scheduler.job.cronExpression\n ? parseCronExpression(scheduler.job.cronExpression, undefined, { timezone: scheduler.job.timezone }).description\n : undefined;\n\n return {\n ...scheduler.job,\n isRunning: scheduler.isRunning,\n timeUntilNextRun: getTimeUntilNextRun(scheduler.job),\n upcomingExecutions,\n cronDescription,\n };\n });\n\n return { jobs, runningExecutions: runtime.runningExecutions };\n};\n\n// Pure function to build the executions view\nexport const createExecutionsSummary = (runtime: SchedulerRuntime) => ({\n executions: runtime.executionHistory.slice(-50), // Last 50 executions\n running: Object.values(runtime.executions).filter(e => e.status === 'running'),\n});\n","import { JobDefinition, JobExecution, JobHandler, ScheduledJob, SchedulerConfig, SchedulerService } from \"./types\";\nimport { detectExpressionType, convertRateToCron } from \"./cron-utils\";\nimport { generateExecutionId, generateJobId, calculateNextRun, calculateNextRunFromLastRun } from \"./utils\";\n\n// Pure function to validate a job definition before it's turned into a job.\n// A job needs exactly one timing source; only validate the cron expression\n// itself when one was actually given (intervalMs/delayMs-only jobs have no\n// cron expression to check).\nexport const validateJobDefinition = (jobDef: JobDefinition): void => {\n if (!jobDef.cronExpression && !jobDef.intervalMs && !jobDef.delayMs) {\n throw new Error(`Job ${jobDef.name} must specify a cronExpression, intervalMs, or delayMs`);\n }\n\n if (jobDef.cronExpression && detectExpressionType(jobDef.cronExpression) === \"unknown\") {\n throw new Error(`Invalid cron expression for job: ${jobDef.name}`);\n }\n};\n\n// Pure function to turn a job definition into a scheduled job\nexport const createJobFromDefinition = (jobDef: JobDefinition, config: SchedulerConfig): ScheduledJob => {\n validateJobDefinition(jobDef);\n\n const expressionType = detectExpressionType(jobDef.cronExpression);\n const cronExpression = expressionType === \"rate\"\n ? convertRateToCron(jobDef.cronExpression!).cronExpression\n : jobDef.cronExpression;\n\n const job: ScheduledJob = {\n id: generateJobId(),\n name: jobDef.name,\n cronExpression,\n intervalMs: jobDef.intervalMs,\n delayMs: jobDef.delayMs,\n nextRun: new Date(),\n enabled: jobDef.enabled ?? true,\n runCount: 0,\n maxRuns: jobDef.maxRuns,\n metadata: jobDef.metadata,\n createdAt: new Date(),\n timezone: jobDef.timezone,\n module: jobDef.module,\n };\n\n job.nextRun = calculateNextRun(job, config.restartBehavior.preserveNaturalTiming);\n return job;\n};\n\n// Pure function to create a scheduler service for a job\nexport const createSchedulerService = (job: ScheduledJob, handler: JobHandler): SchedulerService => ({\n job,\n handler,\n isRunning: false,\n});\n\n// Pure function to create a job execution record\nexport const createJobExecution = (jobId: string): JobExecution => ({\n id: generateExecutionId(),\n jobId,\n startTime: new Date(),\n status: 'running',\n});\n\n// Pure function to mark an execution as finished\nexport const completeExecution = (\n execution: JobExecution,\n result?: any,\n error?: string\n): JobExecution => ({\n ...execution,\n endTime: new Date(),\n status: error ? 'failed' : 'completed',\n result,\n error,\n});\n\n// Pure function to advance a job's run count/timing after an execution\nexport const updateJobAfterExecution = (\n job: ScheduledJob,\n execution: JobExecution,\n config: SchedulerConfig\n): ScheduledJob => {\n const updatedJob: ScheduledJob = {\n ...job,\n lastRun: execution.startTime,\n runCount: job.runCount + 1,\n };\n\n if (updatedJob.enabled) {\n updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, updatedJob.lastRun, config);\n }\n\n return updatedJob;\n};\n\n// Pure function to enable a job and recompute its next run\nexport const enableJob = (scheduler: SchedulerService): SchedulerService => ({\n ...scheduler,\n job: {\n ...scheduler.job,\n enabled: true,\n nextRun: calculateNextRun(scheduler.job),\n },\n});\n\n// Pure function to disable a job\nexport const disableJob = (scheduler: SchedulerService): SchedulerService => ({\n ...scheduler,\n job: { ...scheduler.job, enabled: false },\n});\n","import * as fs from \"fs/promises\";\nimport * as path from \"path\";\n\nimport { JobExecution, ScheduledJob, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { hasJobDefinitionChanged, calculateNextRunFromLastRun } from \"./utils\";\nimport { parseCronExpression } from \"./cron-utils\";\n\ninterface SchedulerStateData {\n jobs: ScheduledJob[];\n executions: JobExecution[];\n savedAt: Date;\n version: string;\n}\n\nconst stateFilePath = (directory: string): string => path.join(directory, 'scheduler-state.json');\n\nconst tempFilePath = (directory: string): string => path.join(directory, `scheduler-state.${Date.now()}.temp.json`);\n\nconst restoreExecutionHistory = (savedExecutions: JobExecution[]): JobExecution[] =>\n savedExecutions.map((exec) => ({\n ...exec,\n startTime: new Date(exec.startTime),\n endTime: exec.endTime ? new Date(exec.endTime) : undefined,\n }));\n\nconst readStateData = async (directory: string): Promise<SchedulerStateData | null> => {\n const data = await fs.readFile(stateFilePath(directory), 'utf8');\n return JSON.parse(data);\n};\n\nexport const saveSchedulerState = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n const stateData: SchedulerStateData = {\n jobs: Object.values(runtime.schedulers).map(s => s.job),\n executions: runtime.executionHistory.slice(-100),\n savedAt: new Date(),\n version: '1.0',\n };\n\n const file = stateFilePath(runtime.config.persistence.directory);\n const temp = tempFilePath(runtime.config.persistence.directory);\n\n // Write to a temp file first, then rename - rename is atomic, so a\n // reader never sees a half-written file.\n await fs.writeFile(temp, JSON.stringify(stateData, null, 2), 'utf8');\n await fs.rename(temp, file);\n\n runtime.logging.debug('Scheduler state saved');\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, 'Failed to save scheduler state');\n }\n};\n\n// Recalculates - or preserves - a restored job's nextRun depending on how\n// long ago the process restarted, so a quick redeploy doesn't lose timing\n// but a long outage doesn't fire a pile of catch-up runs.\nconst validateAndAdjustNextRun = (\n job: ScheduledJob,\n savedNextRun: Date | undefined,\n runtime: SchedulerRuntime\n): Date => {\n const { config, lastRestartTime, logging } = runtime;\n const now = new Date();\n\n if (!savedNextRun || savedNextRun <= now) {\n logging.debug({ module: job.module }, `Saved next run is in the past for ${job.name} - recalculating`);\n return calculateNextRunFromLastRun(job, job.lastRun, config);\n }\n\n const isRapidRestart = now.getTime() - lastRestartTime.getTime() < config.restartBehavior.rapidRestartThreshold;\n if (isRapidRestart) {\n logging.debug({ module: job.module }, `Rapid restart detected for ${job.name} - preserving saved timing`);\n return savedNextRun;\n }\n\n if (job.cronExpression || job.intervalMs) {\n const expectedNextRun = calculateNextRunFromLastRun(job, job.lastRun, config);\n const drift = Math.abs(savedNextRun.getTime() - expectedNextRun.getTime());\n if (drift > config.restartBehavior.maxTimingDrift) {\n logging.debug({ module: job.module }, `Adjusting timing for ${job.name} - drift of ${Math.round(drift / 1000)}s detected`);\n return expectedNextRun;\n }\n }\n\n return savedNextRun;\n};\n\n// Restores this job's saved run history (count, lastRun) and next-run\n// timing from the persisted state file. Mirrors queue-plugin's per-queue\n// loadQueueState: called from addJob right after the scheduler is\n// registered, not at plugin init - the saved file has nothing to match\n// against that early, since no jobs have been added yet.\nexport const loadJobState = async (runtime: SchedulerRuntime, scheduler: SchedulerService): Promise<SchedulerService> => {\n try {\n const stateData = await readStateData(runtime.config.persistence.directory);\n if (!stateData) {\n return scheduler;\n }\n\n const savedJob = stateData.jobs.find(job => job.name === scheduler.job.name);\n if (!savedJob) {\n return scheduler;\n }\n\n const definitionChanged = hasJobDefinitionChanged(scheduler.job, savedJob);\n const lastRun = savedJob.lastRun ? new Date(savedJob.lastRun) : undefined;\n\n const updatedJob: ScheduledJob = {\n ...scheduler.job,\n runCount: savedJob.runCount,\n lastRun,\n };\n\n if (definitionChanged) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job definition changed: ${savedJob.name} - recalculating schedule`);\n updatedJob.nextRun = calculateNextRunFromLastRun(updatedJob, lastRun, runtime.config);\n } else {\n updatedJob.nextRun = validateAndAdjustNextRun(updatedJob, savedJob.nextRun ? new Date(savedJob.nextRun) : undefined, runtime);\n }\n\n if (runtime.config.cron.logCronDetails && updatedJob.cronExpression) {\n const result = parseCronExpression(updatedJob.cronExpression, updatedJob.lastRun, { timezone: updatedJob.timezone });\n runtime.logging.debug(\n { module: scheduler.job.module },\n `Job restored: ${savedJob.name} - ${result.description} - next: ${updatedJob.nextRun.toLocaleString()}`\n );\n } else {\n runtime.logging.debug({ module: scheduler.job.module }, `Job state restored: ${savedJob.name}`);\n }\n\n return { ...scheduler, job: updatedJob };\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n runtime.logging.debug('No saved scheduler state found - starting fresh');\n } else {\n runtime.logging.error({ error: error?.message }, `Failed to load job state for ${scheduler.job.name}`);\n }\n return scheduler;\n }\n};\n\n// Execution history isn't tied to any one job, so it's restored once at\n// plugin init (unlike per-job state, which loadJobState restores lazily as\n// each job is registered).\nexport const loadExecutionHistory = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n const stateData = await readStateData(runtime.config.persistence.directory);\n if (stateData?.executions) {\n runtime.executionHistory = restoreExecutionHistory(stateData.executions);\n }\n } catch (error: any) {\n if (error.code !== 'ENOENT') {\n runtime.logging.error({ error: error?.message }, 'Failed to load execution history');\n }\n }\n};\n\nexport const initializePersistence = async (runtime: SchedulerRuntime): Promise<void> => {\n try {\n await fs.mkdir(runtime.config.persistence.directory, { recursive: true });\n await loadExecutionHistory(runtime);\n\n if (runtime.config.persistence.saveOnShutdown) {\n const shutdownHandler = async () => {\n runtime.logging.debug('Saving scheduler state before shutdown...');\n await saveSchedulerState(runtime);\n process.exit(0);\n };\n\n process.on('SIGINT', shutdownHandler);\n process.on('SIGTERM', shutdownHandler);\n }\n\n runtime.logging.debug(`Scheduler persistence initialized: ${runtime.config.persistence.directory}`);\n } catch (error: any) {\n runtime.logging.error({ error: error?.message }, 'Failed to initialize scheduler persistence');\n }\n};\n","import { JobExecution, JobHandler, ScheduledJob, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { completeExecution, createJobExecution, updateJobAfterExecution } from \"./jobs\";\nimport { isJobReadyToRun, shouldSkipJob } from \"./utils\";\nimport { saveSchedulerState } from \"./persistence\";\n\n// Pure function to check whether a job can run right now\nexport const canExecuteJob = (\n runtime: SchedulerRuntime,\n scheduler: SchedulerService\n): { canExecute: boolean; reason?: string } => {\n if (runtime.isShuttingDown) {\n return { canExecute: false, reason: 'System is shutting down' };\n }\n\n if (scheduler.isRunning) {\n return { canExecute: false, reason: 'Job is already running' };\n }\n\n if (shouldSkipJob(scheduler.job)) {\n const reason = !scheduler.job.enabled ? 'Job is disabled' : 'Job reached maximum runs';\n return { canExecute: false, reason };\n }\n\n if (runtime.runningExecutions >= runtime.config.execution.maxConcurrent) {\n return { canExecute: false, reason: 'Maximum concurrent executions reached' };\n }\n\n return { canExecute: true };\n};\n\nconst executeJobWithTimeout = async (\n handler: JobHandler,\n job: ScheduledJob,\n execution: JobExecution,\n timeoutMs: number\n): Promise<any> => {\n let timerId: NodeJS.Timeout;\n\n try {\n return await Promise.race([\n handler(job, execution),\n new Promise((_, reject) => {\n timerId = setTimeout(() => reject(new Error('Job execution timeout')), timeoutMs);\n }),\n ]);\n } finally {\n clearTimeout(timerId!);\n }\n};\n\n// Runs one job through its handler, recording the execution and advancing\n// its nextRun. Used by both the tick (once per due job) and triggerJob -\n// both go through the same path, wrapped in runWithLogContext by the\n// caller so every log call below carries the job's module/reqId.\nexport const executeJob = async (runtime: SchedulerRuntime, scheduler: SchedulerService): Promise<void> => {\n const execution = createJobExecution(scheduler.job.id);\n // Tracked in two places (the `executions` map and `executionHistory`)\n // but as a single shared reference - completeExecution below mutates\n // this same object via Object.assign so both views stay in sync,\n // instead of completeExecution's return value only updating one of them.\n runtime.executions[execution.id] = execution;\n runtime.executionHistory.push(execution);\n scheduler.isRunning = true;\n runtime.runningExecutions++;\n\n runtime.logging.info(`Executing job ${scheduler.job.name} (${execution.id})`);\n\n try {\n const result = await executeJobWithTimeout(\n scheduler.handler,\n scheduler.job,\n execution,\n runtime.config.execution.defaultTimeout\n );\n\n Object.assign(execution, completeExecution(execution, result));\n\n const duration = execution.endTime!.getTime() - execution.startTime.getTime();\n runtime.logging.debug(`Job completed in ${duration}ms`);\n } catch (error: any) {\n Object.assign(execution, completeExecution(execution, undefined, error.message));\n runtime.logging.error(`Job failed ${scheduler.job.name}: ${error.message}`);\n } finally {\n scheduler.isRunning = false;\n runtime.runningExecutions--;\n scheduler.job = updateJobAfterExecution(scheduler.job, execution, runtime.config);\n\n if (scheduler.job.maxRuns && scheduler.job.runCount >= scheduler.job.maxRuns) {\n runtime.logging.info(`Job ${scheduler.job.name} reached max runs (${scheduler.job.maxRuns})`);\n }\n\n if (runtime.config.persistence.enabled) {\n runtime.isDirty = true;\n }\n }\n};\n\nconst dispatchJobIfDue = (runtime: SchedulerRuntime, scheduler: SchedulerService): void => {\n if (!scheduler.job.enabled || !isJobReadyToRun(scheduler.job)) {\n return;\n }\n\n const { canExecute, reason } = canExecuteJob(runtime, scheduler);\n if (!canExecute) {\n // Not a permanent skip (except the maxRuns case, logged once above\n // instead) - e.g. at max concurrency, or another tick of the same\n // job already running. The job's nextRun hasn't moved, so the very\n // next tick simply tries again, instead of the old per-job timer\n // needing to be explicitly rescheduled with a delay. Logged at\n // debug to avoid spamming at tick frequency.\n if (reason === 'Maximum concurrent executions reached') {\n runtime.logging.debug({ module: scheduler.job.module }, `Delaying job ${scheduler.job.name} - ${reason}`);\n }\n return;\n }\n\n runtime.logging.runWithLogContext(\n { module: scheduler.job.module, reqId: scheduler.job.id },\n () => executeJob(runtime, scheduler)\n );\n};\n\nexport const cleanupExecutionHistory = (runtime: SchedulerRuntime): void => {\n const { maxExecutionHistory } = runtime.config.cleanup;\n if (runtime.executionHistory.length <= maxExecutionHistory) {\n return;\n }\n\n const removed = runtime.executionHistory.splice(0, runtime.executionHistory.length - maxExecutionHistory);\n runtime.logging.debug(`Cleaned up ${removed.length} old execution records`);\n};\n\nconst maybeCleanup = (runtime: SchedulerRuntime, now: number): void => {\n if (now - runtime.lastCleanupTime < runtime.config.cleanup.cleanupInterval) {\n return;\n }\n runtime.lastCleanupTime = now;\n cleanupExecutionHistory(runtime);\n};\n\nconst maybeSavePersistence = (runtime: SchedulerRuntime, now: number): void => {\n if (!runtime.config.persistence.enabled || !runtime.isDirty) {\n return;\n }\n\n const saveInterval = runtime.config.persistence.saveInterval ?? 0;\n if (saveInterval > 0 && now - runtime.lastSavedAt >= saveInterval) {\n runtime.lastSavedAt = now;\n runtime.isDirty = false;\n saveSchedulerState(runtime);\n }\n};\n\n// The one timer for the whole plugin. Every tickIntervalMs: run any job\n// whose nextRun has arrived (this is also how a manual triggerJob's\n// recurrence shows up - nothing schedules its own setTimeout anymore); then\n// clean up old execution history and save persistence if their intervals\n// have elapsed.\nexport const tick = (runtime: SchedulerRuntime): void => {\n const now = Date.now();\n for (const scheduler of Object.values(runtime.schedulers)) {\n dispatchJobIfDue(runtime, scheduler);\n }\n maybeCleanup(runtime, now);\n maybeSavePersistence(runtime, now);\n};\n","import { JobDefinition, JobHandler, SchedulerManager, SchedulerRuntime, SchedulerService } from \"./types\";\nimport { createJobFromDefinition, createSchedulerService, disableJob as disableJobData, enableJob as enableJobData } from \"./jobs\";\nimport { createDashboardSummary, createExecutionsSummary } from \"./core\";\nimport { getNextExecutions, parseCronExpression } from \"./cron-utils\";\nimport { loadJobState } from \"./persistence\";\nimport { executeJob } from \"./processing\";\n\nconst isValidJobName = (jobName: string): boolean => {\n return typeof jobName === 'string' && jobName.length > 0 && /^[a-zA-Z0-9_-]+$/.test(jobName);\n};\n\nconst validateJobName = (jobName: string): void => {\n if (!jobName || typeof jobName !== 'string') {\n throw new Error('Job name must be a non-empty string');\n }\n\n if (!isValidJobName(jobName)) {\n throw new Error('Job name must contain only alphanumeric characters, hyphens, and underscores');\n }\n};\n\nconst validateHandler = (handler: JobHandler): void => {\n if (typeof handler !== 'function') {\n throw new Error('Handler must be a function');\n }\n};\n\nconst findSchedulerByName = (runtime: SchedulerRuntime, jobName: string): SchedulerService | undefined =>\n Object.values(runtime.schedulers).find(scheduler => scheduler.job.name === jobName);\n\nexport const addJob = async (runtime: SchedulerRuntime, jobDefinition: JobDefinition): Promise<string> => {\n try {\n validateJobName(jobDefinition.name);\n validateHandler(jobDefinition.handler);\n\n const existing = findSchedulerByName(runtime, jobDefinition.name);\n if (existing) {\n runtime.logging.warn({ module: jobDefinition.module }, `Job already exists: ${jobDefinition.name}.`);\n return existing.job.id;\n }\n\n const job = createJobFromDefinition(jobDefinition, runtime.config);\n\n if (runtime.config.cron.logCronDetails && job.cronExpression) {\n const timezone = job.timezone ?? runtime.config.cron.defaultTimezone;\n const result = parseCronExpression(job.cronExpression, undefined, { timezone });\n runtime.logging.debug(\n { module: jobDefinition.module },\n `Job ${jobDefinition.name}: ${result.description} - Next: ${result.nextRun.toLocaleString()}`\n );\n\n const upcoming = getNextExecutions(job.cronExpression, 3, { timezone });\n runtime.logging.debug(\n { module: jobDefinition.module },\n `Upcoming: ${upcoming.map(d => d.toLocaleTimeString()).join(', ')}`\n );\n }\n\n let scheduler = createSchedulerService(job, jobDefinition.handler);\n\n if (runtime.config.persistence.enabled) {\n scheduler = await loadJobState(runtime, scheduler);\n }\n\n runtime.schedulers[scheduler.job.id] = scheduler;\n\n runtime.logging.info({ module: jobDefinition.module }, `Job added: ${jobDefinition.name} (${scheduler.job.id})`);\n\n return scheduler.job.id;\n } catch (error: any) {\n runtime.logging.error({ module: jobDefinition.module, error: error.message }, `Failed to add job ${jobDefinition.name}`);\n throw error;\n }\n};\n\nexport const removeJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.isRunning) {\n runtime.logging.warn({ module: scheduler.job.module }, `Removing job that is currently running: ${jobName}`);\n }\n\n delete runtime.schedulers[scheduler.job.id];\n\n runtime.logging.info({ module: scheduler.job.module }, `Job removed: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to remove job ${jobName}`);\n throw error;\n }\n};\n\nexport const hasJob = (runtime: SchedulerRuntime, jobName: string): boolean => {\n try {\n validateJobName(jobName);\n return !!findSchedulerByName(runtime, jobName);\n } catch {\n return false;\n }\n};\n\nexport const listJobs = (runtime: SchedulerRuntime, module?: string): string[] => {\n return Object.values(runtime.schedulers)\n .filter(scheduler => !module || scheduler.job.module === module)\n .map(scheduler => scheduler.job.name)\n .sort();\n};\n\nexport const getJobStats = (runtime: SchedulerRuntime, jobName: string): SchedulerService | null => {\n try {\n validateJobName(jobName);\n return findSchedulerByName(runtime, jobName) ?? null;\n } catch {\n return null;\n }\n};\n\nexport const getJobsMap = (runtime: SchedulerRuntime): Record<string, SchedulerService> => {\n // Return a copy to prevent external modification\n return { ...runtime.schedulers };\n};\n\nexport const enableJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.job.enabled) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job is already enabled: ${jobName}`);\n return;\n }\n\n runtime.schedulers[scheduler.job.id] = enableJobData(scheduler);\n runtime.logging.info({ module: scheduler.job.module }, `Job enabled: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to enable job ${jobName}`);\n throw error;\n }\n};\n\nexport const disableJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (!scheduler.job.enabled) {\n runtime.logging.debug({ module: scheduler.job.module }, `Job is already disabled: ${jobName}`);\n return;\n }\n\n runtime.schedulers[scheduler.job.id] = disableJobData(scheduler);\n runtime.logging.info({ module: scheduler.job.module }, `Job disabled: ${jobName}`);\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to disable job ${jobName}`);\n throw error;\n }\n};\n\nexport const triggerJob = async (runtime: SchedulerRuntime, jobName: string): Promise<void> => {\n try {\n validateJobName(jobName);\n\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n throw new Error(`Job '${jobName}' does not exist`);\n }\n\n if (scheduler.isRunning) {\n throw new Error(`Job '${jobName}' is already running`);\n }\n\n runtime.logging.info({ module: scheduler.job.module }, `Job triggered: ${jobName}`);\n\n // Fire-and-forget, same as the tick's own dispatch - callers (e.g.\n // the trigger route) get an immediate response rather than waiting\n // out the job's full run.\n runtime.logging.runWithLogContext(\n { module: scheduler.job.module, reqId: scheduler.job.id },\n () => executeJob(runtime, scheduler)\n );\n } catch (error: any) {\n runtime.logging.error({ error: error.message }, `Failed to trigger job ${jobName}`);\n throw error;\n }\n};\n\nexport const getDashboardSummary = (runtime: SchedulerRuntime) => createDashboardSummary(runtime);\n\nexport const getExecutionsSummary = (runtime: SchedulerRuntime) => createExecutionsSummary(runtime);\n\n// Unlike getExecutionsSummary (last 50 across every job), this filters the\n// full executionHistory down to one job first - so a busy job elsewhere\n// can't push a quieter job's own runs out of view.\nexport const getJobExecutionHistory = (runtime: SchedulerRuntime, jobName: string, limit = 50) => {\n const scheduler = findSchedulerByName(runtime, jobName);\n if (!scheduler) {\n return [];\n }\n\n return runtime.executionHistory\n .filter(execution => execution.jobId === scheduler.job.id)\n .slice(-limit)\n .reverse();\n};\n\n// The one place runtime gets bound into the public app.scheduler shape -\n// Fastify needs a plain object of methods with no runtime param, so this\n// wraps each plain function above with `runtime` pre-applied. Everything\n// above this line is a normal function you can call directly with an\n// explicit runtime, e.g. in tests.\nexport const createSchedulerManager = (runtime: SchedulerRuntime): SchedulerManager => ({\n addJob: (jobDefinition) => addJob(runtime, jobDefinition),\n removeJob: (jobName) => removeJob(runtime, jobName),\n hasJob: (jobName) => hasJob(runtime, jobName),\n listJobs: (module) => listJobs(runtime, module),\n getJobStats: (jobName) => getJobStats(runtime, jobName),\n getJobsMap: () => getJobsMap(runtime),\n getConfig: () => runtime.config,\n enableJob: (jobName) => enableJob(runtime, jobName),\n disableJob: (jobName) => disableJob(runtime, jobName),\n triggerJob: (jobName) => triggerJob(runtime, jobName),\n getDashboardSummary: () => getDashboardSummary(runtime),\n getExecutionsSummary: () => getExecutionsSummary(runtime),\n getJobExecutionHistory: (jobName, limit) => getJobExecutionHistory(runtime, jobName, limit),\n});\n","import { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\n\n// Function to register all routes\nexport const registerSchedulerRoutes = (\n app: FastifyInstance,\n prefix: string = \"schedule\"\n): void => {\n app.get(`/${prefix}/dashboard`,\n async (_: FastifyRequest, reply: FastifyReply) => {\n return reply.status(200).send(app.scheduler.getDashboardSummary());\n });\n\n app.get(`/${prefix}/executions`,\n async (_: FastifyRequest, reply: FastifyReply) => {\n return reply.status(200).send(app.scheduler.getExecutionsSummary());\n });\n\n app.post<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/trigger`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.triggerJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job triggered successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n\n app.put<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/enable`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.enableJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job enabled successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n\n app.put<{ Params: { jobName: string } }>(`/${prefix}/jobs/:jobName/disable`,\n async (request: FastifyRequest<{ Params: { jobName: string } }>, reply: FastifyReply) => {\n try {\n await app.scheduler.disableJob(request.params.jobName);\n return reply.status(200).send({ message: \"Job disabled successfully\" });\n } catch (error: any) {\n return reply.status(404).send({ error: error.message });\n }\n });\n};\n"],"mappings":"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","names":["enableJob","disableJob"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudnux/local-cloud-provider",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "CloudNux local development cloud provider implementation",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -55,7 +55,7 @@
55
55
  "clean": "rm -rf dist"
56
56
  },
57
57
  "dependencies": {
58
- "@cloudnux/core-cloud-provider": "0.20.0",
58
+ "@cloudnux/core-cloud-provider": "0.21.0",
59
59
  "@fastify/cors": "^11.1.0",
60
60
  "@fastify/static": "^8.0.0",
61
61
  "@fastify/websocket": "^11.0.1",