@warlock.js/scheduler 4.0.39 → 4.0.41
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.
- package/cjs/index.js +976 -1
- package/cjs/index.js.map +1 -1
- package/esm/index.js +963 -1
- package/esm/index.js.map +1 -1
- package/package.json +1 -1
package/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../warlock.js/scheduler/src/cron-parser.ts","../../../../../../../warlock.js/scheduler/src/job.ts","../../../../../../../warlock.js/scheduler/src/scheduler.ts"],"names":["CronParser","_expression","from","dayjs","date","maxIterations","iterations","expression","parts","minute","hour","dayOfMonth","month","dayOfWeek","field","min","max","values","part","range","stepStr","step","rangeStart","rangeEnd","startStr","endStr","value","i","a","b","parseCron","utc","timezone","DAYS_OF_WEEK","Job","name","_callback","timeType","seconds","minutes","hours","day","time","type","now","tz","skip","maxRetries","delay","backoffMultiplier","startTime","result","error","resolve","lastError","attempts","maxAttempts","attempt","ms","targetDay","second","job","callback","Scheduler","EventEmitter","jobCallback","jobs","jobName","index","j","parallel","maxConcurrency","timeout","runningJobs","elapsed","dueJobs","batches","batch","scheduler"],"mappings":"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","file":"index.js","sourcesContent":["import dayjs, { type Dayjs } from \"dayjs\";\n\n/**\n * Parsed cron expression fields\n */\nexport type CronFields = {\n /** Minutes (0-59) */\n minutes: number[];\n /** Hours (0-23) */\n hours: number[];\n /** Days of month (1-31) */\n daysOfMonth: number[];\n /** Months (1-12) */\n months: number[];\n /** Days of week (0-6, Sunday = 0) */\n daysOfWeek: number[];\n};\n\n/**\n * Cron expression parser\n *\n * Supports standard 5-field cron expressions:\n * ```\n * ┌───────────── minute (0-59)\n * │ ┌───────────── hour (0-23)\n * │ │ ┌───────────── day of month (1-31)\n * │ │ │ ┌───────────── month (1-12)\n * │ │ │ │ ┌───────────── day of week (0-6, Sunday = 0)\n * │ │ │ │ │\n * * * * * *\n * ```\n *\n * Supports:\n * - `*` - any value\n * - `5` - specific value\n * - `1,3,5` - list of values\n * - `1-5` - range of values\n * - `* /5` - step values (every 5)\n * - `1-10/2` - range with step\n *\n * @example\n * ```typescript\n * const parser = new CronParser(\"0 9 * * 1-5\"); // 9 AM weekdays\n * const nextRun = parser.nextRun();\n * ```\n */\nexport class CronParser {\n private readonly _fields: CronFields;\n\n /**\n * Creates a new CronParser instance\n *\n * @param expression - Standard 5-field cron expression\n * @throws Error if expression is invalid\n */\n public constructor(private readonly _expression: string) {\n this._fields = this._parse(_expression);\n }\n\n /**\n * Get the parsed cron fields\n */\n public get fields(): Readonly<CronFields> {\n return this._fields;\n }\n\n /**\n * Get the original expression\n */\n public get expression(): string {\n return this._expression;\n }\n\n /**\n * Calculate the next run time from a given date\n *\n * @param from - Starting date (defaults to now)\n * @returns Next run time as Dayjs\n */\n public nextRun(from: Dayjs = dayjs()): Dayjs {\n let date = from.add(1, \"minute\").second(0).millisecond(0);\n\n // Maximum iterations to prevent infinite loops\n const maxIterations = 366 * 24 * 60; // 1 year of minutes\n let iterations = 0;\n\n while (iterations < maxIterations) {\n iterations++;\n\n // Check month\n if (!this._fields.months.includes(date.month() + 1)) {\n date = date.add(1, \"month\").date(1).hour(0).minute(0);\n continue;\n }\n\n // Check day of month\n if (!this._fields.daysOfMonth.includes(date.date())) {\n date = date.add(1, \"day\").hour(0).minute(0);\n continue;\n }\n\n // Check day of week\n if (!this._fields.daysOfWeek.includes(date.day())) {\n date = date.add(1, \"day\").hour(0).minute(0);\n continue;\n }\n\n // Check hour\n if (!this._fields.hours.includes(date.hour())) {\n date = date.add(1, \"hour\").minute(0);\n continue;\n }\n\n // Check minute\n if (!this._fields.minutes.includes(date.minute())) {\n date = date.add(1, \"minute\");\n continue;\n }\n\n // All fields match!\n return date;\n }\n\n throw new Error(`Could not find next run time for cron expression: ${this._expression}`);\n }\n\n /**\n * Check if a given date matches the cron expression\n *\n * @param date - Date to check\n * @returns true if the date matches\n */\n public matches(date: Dayjs): boolean {\n return (\n this._fields.minutes.includes(date.minute()) &&\n this._fields.hours.includes(date.hour()) &&\n this._fields.daysOfMonth.includes(date.date()) &&\n this._fields.months.includes(date.month() + 1) &&\n this._fields.daysOfWeek.includes(date.day())\n );\n }\n\n /**\n * Parse a cron expression into fields\n */\n private _parse(expression: string): CronFields {\n const parts = expression.trim().split(/\\s+/);\n\n if (parts.length !== 5) {\n throw new Error(\n `Invalid cron expression: \"${expression}\". Expected 5 fields (minute hour day month weekday).`,\n );\n }\n\n const [minute, hour, dayOfMonth, month, dayOfWeek] = parts;\n\n return {\n minutes: this._parseField(minute, 0, 59),\n hours: this._parseField(hour, 0, 23),\n daysOfMonth: this._parseField(dayOfMonth, 1, 31),\n months: this._parseField(month, 1, 12),\n daysOfWeek: this._parseField(dayOfWeek, 0, 6),\n };\n }\n\n /**\n * Parse a single cron field\n *\n * @param field - Field value (e.g., \"*\", \"5\", \"1-5\", \"* /2\", \"1,3,5\")\n * @param min - Minimum allowed value\n * @param max - Maximum allowed value\n * @returns Array of matching values\n */\n private _parseField(field: string, min: number, max: number): number[] {\n const values = new Set<number>();\n\n // Handle lists (e.g., \"1,3,5\")\n const parts = field.split(\",\");\n\n for (const part of parts) {\n // Handle step values (e.g., \"*/5\" or \"1-10/2\")\n const [range, stepStr] = part.split(\"/\");\n const step = stepStr ? parseInt(stepStr, 10) : 1;\n\n if (isNaN(step) || step < 1) {\n throw new Error(`Invalid step value in cron field: \"${field}\"`);\n }\n\n let rangeStart: number;\n let rangeEnd: number;\n\n if (range === \"*\") {\n // Wildcard - all values\n rangeStart = min;\n rangeEnd = max;\n } else if (range.includes(\"-\")) {\n // Range (e.g., \"1-5\")\n const [startStr, endStr] = range.split(\"-\");\n rangeStart = parseInt(startStr, 10);\n rangeEnd = parseInt(endStr, 10);\n\n if (isNaN(rangeStart) || isNaN(rangeEnd)) {\n throw new Error(`Invalid range in cron field: \"${field}\"`);\n }\n\n if (rangeStart < min || rangeEnd > max || rangeStart > rangeEnd) {\n throw new Error(`Range out of bounds in cron field: \"${field}\" (valid: ${min}-${max})`);\n }\n } else {\n // Single value\n const value = parseInt(range, 10);\n\n if (isNaN(value)) {\n throw new Error(`Invalid value in cron field: \"${field}\"`);\n }\n\n if (value < min || value > max) {\n throw new Error(`Value out of bounds in cron field: \"${field}\" (valid: ${min}-${max})`);\n }\n\n rangeStart = value;\n rangeEnd = value;\n }\n\n // Add values with step\n for (let i = rangeStart; i <= rangeEnd; i += step) {\n values.add(i);\n }\n }\n\n return Array.from(values).sort((a, b) => a - b);\n }\n}\n\n/**\n * Parse a cron expression string\n *\n * @param expression - Cron expression (5 fields)\n * @returns CronParser instance\n */\nexport function parseCron(expression: string): CronParser {\n return new CronParser(expression);\n}\n","import dayjs, { type Dayjs } from \"dayjs\";\r\nimport timezone from \"dayjs/plugin/timezone.js\";\r\nimport utc from \"dayjs/plugin/utc.js\";\r\nimport { CronParser } from \"./cron-parser\";\r\nimport type { Day, JobIntervals, JobResult, RetryConfig, TimeType } from \"./types\";\r\n\r\n// Enable timezone support\r\ndayjs.extend(utc);\r\ndayjs.extend(timezone);\r\n\r\nexport type JobCallback = (job: Job) => Promise<any>;\r\n\r\n/**\r\n * Days of week mapping (lowercase for consistency with Day type)\r\n */\r\nconst DAYS_OF_WEEK: Day[] = [\r\n \"sunday\",\r\n \"monday\",\r\n \"tuesday\",\r\n \"wednesday\",\r\n \"thursday\",\r\n \"friday\",\r\n \"saturday\",\r\n];\r\n\r\n/**\r\n * Job class represents a scheduled task with configurable timing and execution options.\r\n *\r\n * @example\r\n * ```typescript\r\n * const job = new Job(\"cleanup\", async () => {\r\n * await cleanupOldFiles();\r\n * })\r\n * .everyDay()\r\n * .at(\"03:00\")\r\n * .inTimezone(\"America/New_York\")\r\n * .preventOverlap()\r\n * .retry(3, 1000);\r\n * ```\r\n */\r\nexport class Job {\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Private Properties\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Interval configuration for scheduling\r\n */\r\n private _intervals: JobIntervals = {};\r\n\r\n /**\r\n * Last execution timestamp\r\n */\r\n private _lastRun: Dayjs | null = null;\r\n\r\n /**\r\n * Whether the job is currently executing\r\n */\r\n private _isRunning = false;\r\n\r\n /**\r\n * Skip execution if job is already running\r\n */\r\n private _skipIfRunning = false;\r\n\r\n /**\r\n * Retry configuration\r\n */\r\n private _retryConfig: RetryConfig | null = null;\r\n\r\n /**\r\n * Timezone for scheduling (defaults to system timezone)\r\n */\r\n private _timezone: string | null = null;\r\n\r\n /**\r\n * Cron expression parser (mutually exclusive with interval config)\r\n */\r\n private _cronParser: CronParser | null = null;\r\n\r\n /**\r\n * Promise resolver for completion waiting\r\n */\r\n private _completionResolver: (() => void) | null = null;\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Public Properties\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Next scheduled execution time\r\n */\r\n public nextRun: Dayjs | null = null;\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Constructor\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Creates a new Job instance\r\n *\r\n * @param name - Unique identifier for the job\r\n * @param callback - Function to execute when the job runs\r\n */\r\n public constructor(\r\n public readonly name: string,\r\n private readonly _callback: JobCallback,\r\n ) {}\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Public Getters\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Returns true if the job is currently executing\r\n */\r\n public get isRunning(): boolean {\r\n return this._isRunning;\r\n }\r\n\r\n /**\r\n * Returns the last execution timestamp\r\n */\r\n public get lastRun(): Dayjs | null {\r\n return this._lastRun;\r\n }\r\n\r\n /**\r\n * Returns the current interval configuration (readonly)\r\n */\r\n public get intervals(): Readonly<JobIntervals> {\r\n return this._intervals;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Interval Configuration Methods (Fluent API)\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Set a custom interval for job execution\r\n *\r\n * @param value - Number of time units\r\n * @param timeType - Type of time unit\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.every(5, \"minute\"); // Run every 5 minutes\r\n * job.every(2, \"hour\"); // Run every 2 hours\r\n * ```\r\n */\r\n public every(value: number, timeType: TimeType): this {\r\n this._intervals.every = { type: timeType, value };\r\n return this;\r\n }\r\n\r\n /**\r\n * Run job every second (use with caution - high frequency)\r\n */\r\n public everySecond(): this {\r\n return this.every(1, \"second\");\r\n }\r\n\r\n /**\r\n * Run job every specified number of seconds\r\n */\r\n public everySeconds(seconds: number): this {\r\n return this.every(seconds, \"second\");\r\n }\r\n\r\n /**\r\n * Run job every minute\r\n */\r\n public everyMinute(): this {\r\n return this.every(1, \"minute\");\r\n }\r\n\r\n /**\r\n * Run job every specified number of minutes\r\n */\r\n public everyMinutes(minutes: number): this {\r\n return this.every(minutes, \"minute\");\r\n }\r\n\r\n /**\r\n * Run job every hour\r\n */\r\n public everyHour(): this {\r\n return this.every(1, \"hour\");\r\n }\r\n\r\n /**\r\n * Run job every specified number of hours\r\n */\r\n public everyHours(hours: number): this {\r\n return this.every(hours, \"hour\");\r\n }\r\n\r\n /**\r\n * Run job every day at midnight\r\n */\r\n public everyDay(): this {\r\n return this.every(1, \"day\");\r\n }\r\n\r\n /**\r\n * Alias for everyDay()\r\n */\r\n public daily(): this {\r\n return this.everyDay();\r\n }\r\n\r\n /**\r\n * Run job twice a day (every 12 hours)\r\n */\r\n public twiceDaily(): this {\r\n return this.every(12, \"hour\");\r\n }\r\n\r\n /**\r\n * Run job every week\r\n */\r\n public everyWeek(): this {\r\n return this.every(1, \"week\");\r\n }\r\n\r\n /**\r\n * Alias for everyWeek()\r\n */\r\n public weekly(): this {\r\n return this.everyWeek();\r\n }\r\n\r\n /**\r\n * Run job every month\r\n */\r\n public everyMonth(): this {\r\n return this.every(1, \"month\");\r\n }\r\n\r\n /**\r\n * Alias for everyMonth()\r\n */\r\n public monthly(): this {\r\n return this.everyMonth();\r\n }\r\n\r\n /**\r\n * Run job every year\r\n */\r\n public everyYear(): this {\r\n return this.every(1, \"year\");\r\n }\r\n\r\n /**\r\n * Alias for everyYear()\r\n */\r\n public yearly(): this {\r\n return this.everyYear();\r\n }\r\n\r\n /**\r\n * Alias for everyMinute() - job runs continuously every minute\r\n */\r\n public always(): this {\r\n return this.everyMinute();\r\n }\r\n\r\n /**\r\n * Schedule job using a cron expression\r\n *\r\n * Supports standard 5-field cron syntax:\r\n * ```\r\n * ┌───────────── minute (0-59)\r\n * │ ┌───────────── hour (0-23)\r\n * │ │ ┌───────────── day of month (1-31)\r\n * │ │ │ ┌───────────── month (1-12)\r\n * │ │ │ │ ┌───────────── day of week (0-6, Sunday = 0)\r\n * │ │ │ │ │\r\n * * * * * *\r\n * ```\r\n *\r\n * Supports:\r\n * - '*' - any value\r\n * - '5' - specific value\r\n * - '1,3,5' - list of values\r\n * - '1-5' - range of values\r\n * - 'x/5' - step values (every 5)\r\n * - '1-10/2' - range with step\r\n *\r\n * @param expression - Standard 5-field cron expression\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.cron(\"0 9 * * 1-5\"); // 9 AM weekdays\r\n * job.cron(\"x/5 * * * *\"); // Every 5 minutes\r\n * job.cron(\"0 0 1 * *\"); // First day of month at midnight\r\n * job.cron(\"0 x/2 * * *\"); // Every 2 hours\r\n * ```\r\n */\r\n public cron(expression: string): this {\r\n this._cronParser = new CronParser(expression);\r\n // Clear interval config since cron takes precedence\r\n this._intervals = {};\r\n return this;\r\n }\r\n\r\n /**\r\n * Get the cron expression if one is set\r\n */\r\n public get cronExpression(): string | null {\r\n return this._cronParser?.expression ?? null;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Day & Time Configuration Methods\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Schedule job on a specific day\r\n *\r\n * @param day - Day of week (string) or day of month (number 1-31)\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.on(\"monday\"); // Run on Mondays\r\n * job.on(15); // Run on the 15th of each month\r\n * ```\r\n */\r\n public on(day: Day | number): this {\r\n if (typeof day === \"number\" && (day < 1 || day > 31)) {\r\n throw new Error(\"Invalid day of the month. Must be between 1 and 31.\");\r\n }\r\n\r\n this._intervals.day = day;\r\n return this;\r\n }\r\n\r\n /**\r\n * Schedule job at a specific time\r\n *\r\n * @param time - Time in HH:mm or HH:mm:ss format\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.daily().at(\"09:00\"); // Run daily at 9 AM\r\n * job.weekly().at(\"14:30\"); // Run weekly at 2:30 PM\r\n * ```\r\n */\r\n public at(time: string): this {\r\n // Validate time format\r\n if (!/^\\d{1,2}:\\d{2}(:\\d{2})?$/.test(time)) {\r\n throw new Error(\"Invalid time format. Use HH:mm or HH:mm:ss.\");\r\n }\r\n\r\n this._intervals.time = time;\r\n return this;\r\n }\r\n\r\n /**\r\n * Run task at the beginning of the specified time period\r\n *\r\n * @param type - Time type (day, month, year)\r\n */\r\n public beginOf(type: TimeType): this {\r\n const time = \"00:00\";\r\n\r\n switch (type) {\r\n case \"day\":\r\n break;\r\n case \"month\":\r\n this.on(1);\r\n break;\r\n case \"year\":\r\n this.on(1);\r\n this.every(1, \"year\");\r\n break;\r\n default:\r\n throw new Error(`Unsupported type for beginOf: ${type}`);\r\n }\r\n\r\n return this.at(time);\r\n }\r\n\r\n /**\r\n * Run task at the end of the specified time period\r\n *\r\n * @param type - Time type (day, month, year)\r\n */\r\n public endOf(type: TimeType): this {\r\n const now = this._now();\r\n const time = \"23:59\";\r\n\r\n switch (type) {\r\n case \"day\":\r\n break;\r\n case \"month\":\r\n this.on(now.endOf(\"month\").date());\r\n break;\r\n case \"year\":\r\n this.on(31);\r\n this.every(1, \"year\");\r\n break;\r\n default:\r\n throw new Error(`Unsupported type for endOf: ${type}`);\r\n }\r\n\r\n return this.at(time);\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Timezone Configuration\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Set the timezone for this job's scheduling\r\n *\r\n * @param tz - IANA timezone string (e.g., \"America/New_York\", \"Europe/London\")\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.daily().at(\"09:00\").inTimezone(\"America/New_York\");\r\n * ```\r\n */\r\n public inTimezone(tz: string): this {\r\n this._timezone = tz;\r\n return this;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Execution Options\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Prevent overlapping executions of this job\r\n *\r\n * When enabled, if the job is already running when it's scheduled to run again,\r\n * the new execution will be skipped.\r\n *\r\n * @param skip - Whether to skip if already running (default: true)\r\n * @returns this for chaining\r\n */\r\n public preventOverlap(skip = true): this {\r\n this._skipIfRunning = skip;\r\n return this;\r\n }\r\n\r\n /**\r\n * Configure automatic retry on failure\r\n *\r\n * @param maxRetries - Maximum number of retry attempts\r\n * @param delay - Delay between retries in milliseconds\r\n * @param backoffMultiplier - Optional multiplier for exponential backoff\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.retry(3, 1000); // Retry 3 times with 1s delay\r\n * job.retry(5, 1000, 2); // Exponential backoff: 1s, 2s, 4s, 8s, 16s\r\n * ```\r\n */\r\n public retry(maxRetries: number, delay = 1000, backoffMultiplier?: number): this {\r\n this._retryConfig = {\r\n maxRetries,\r\n delay,\r\n backoffMultiplier,\r\n };\r\n return this;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Execution Control\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Terminate the job and clear all scheduling data\r\n */\r\n public terminate(): this {\r\n this._intervals = {};\r\n this.nextRun = null;\r\n this._lastRun = null;\r\n this._isRunning = false;\r\n return this;\r\n }\r\n\r\n /**\r\n * Prepare the job by calculating the next run time\r\n * Called by the scheduler when starting\r\n */\r\n public prepare(): void {\r\n this._determineNextRun();\r\n }\r\n\r\n /**\r\n * Determine if the job should run now\r\n *\r\n * @returns true if the job should execute\r\n */\r\n public shouldRun(): boolean {\r\n // Skip if already running and overlap prevention is enabled\r\n if (this._skipIfRunning && this._isRunning) {\r\n return false;\r\n }\r\n\r\n return this.nextRun !== null && this._now().isAfter(this.nextRun);\r\n }\r\n\r\n /**\r\n * Execute the job\r\n *\r\n * @returns Promise resolving to the job result\r\n */\r\n public async run(): Promise<JobResult> {\r\n const startTime = Date.now();\r\n let retries = 0;\r\n\r\n this._isRunning = true;\r\n\r\n try {\r\n const result = await this._executeWithRetry();\r\n this._lastRun = this._now();\r\n this._determineNextRun();\r\n\r\n return {\r\n success: true,\r\n duration: Date.now() - startTime,\r\n retries: result.retries || 0,\r\n };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n duration: Date.now() - startTime,\r\n error,\r\n retries: this._retryConfig?.maxRetries ?? 0,\r\n };\r\n } finally {\r\n this._isRunning = false;\r\n\r\n // Resolve any waiting completion promises\r\n if (this._completionResolver) {\r\n this._completionResolver();\r\n this._completionResolver = null;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Wait for the job to complete\r\n * Useful for graceful shutdown\r\n *\r\n * @returns Promise that resolves when the job completes\r\n */\r\n public waitForCompletion(): Promise<void> {\r\n if (!this._isRunning) {\r\n return Promise.resolve();\r\n }\r\n\r\n return new Promise((resolve) => {\r\n this._completionResolver = resolve;\r\n });\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Private Methods\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Get current time, respecting timezone if set\r\n */\r\n private _now(): Dayjs {\r\n return this._timezone ? dayjs().tz(this._timezone) : dayjs();\r\n }\r\n\r\n /**\r\n * Execute the callback with retry logic\r\n */\r\n private async _executeWithRetry(): Promise<{ retries: number }> {\r\n let lastError: unknown;\r\n let attempts = 0;\r\n const maxAttempts = (this._retryConfig?.maxRetries ?? 0) + 1;\r\n\r\n while (attempts < maxAttempts) {\r\n try {\r\n await this._callback(this);\r\n return { retries: attempts };\r\n } catch (error) {\r\n lastError = error;\r\n attempts++;\r\n\r\n if (attempts < maxAttempts && this._retryConfig) {\r\n const delay = this._calculateRetryDelay(attempts);\r\n await this._sleep(delay);\r\n }\r\n }\r\n }\r\n\r\n throw lastError;\r\n }\r\n\r\n /**\r\n * Calculate retry delay with optional exponential backoff\r\n */\r\n private _calculateRetryDelay(attempt: number): number {\r\n if (!this._retryConfig) return 0;\r\n\r\n const { delay, backoffMultiplier } = this._retryConfig;\r\n\r\n if (backoffMultiplier) {\r\n return delay * Math.pow(backoffMultiplier, attempt - 1);\r\n }\r\n\r\n return delay;\r\n }\r\n\r\n /**\r\n * Sleep for specified milliseconds\r\n */\r\n private _sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n }\r\n\r\n /**\r\n * Calculate the next run time based on interval or cron configuration\r\n */\r\n private _determineNextRun(): void {\r\n // If using cron expression, delegate to cron parser\r\n if (this._cronParser) {\r\n const now = this._now();\r\n this.nextRun = this._cronParser.nextRun(now);\r\n return;\r\n }\r\n\r\n // Otherwise use interval-based scheduling\r\n let date = this._lastRun ? this._lastRun.add(1, \"second\") : this._now();\r\n\r\n // Apply interval\r\n if (this._intervals.every?.value && this._intervals.every?.type) {\r\n date = date.add(this._intervals.every.value, this._intervals.every.type);\r\n }\r\n\r\n // Apply day constraint\r\n if (this._intervals.day !== undefined) {\r\n if (typeof this._intervals.day === \"number\") {\r\n date = date.date(this._intervals.day);\r\n } else {\r\n const targetDay = DAYS_OF_WEEK.indexOf(this._intervals.day);\r\n if (targetDay !== -1) {\r\n date = date.day(targetDay);\r\n }\r\n }\r\n }\r\n\r\n // Apply time constraint\r\n if (this._intervals.time) {\r\n const parts = this._intervals.time.split(\":\").map(Number);\r\n const [hour, minute, second = 0] = parts;\r\n date = date.hour(hour).minute(minute).second(second).millisecond(0);\r\n }\r\n\r\n // Ensure the next run is in the future\r\n while (date.isBefore(this._now())) {\r\n if (this._intervals.every?.value && this._intervals.every?.type) {\r\n date = date.add(this._intervals.every.value, this._intervals.every.type);\r\n } else {\r\n // Default to adding one day if there's no specific interval defined\r\n date = date.add(1, \"day\");\r\n }\r\n }\r\n\r\n this.nextRun = date;\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────────\r\n// Factory Function\r\n// ─────────────────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Factory function to create a new Job instance\r\n *\r\n * @param name - Unique identifier for the job\r\n * @param callback - Function to execute when the job runs\r\n * @returns New Job instance\r\n *\r\n * @example\r\n * ```typescript\r\n * const cleanupJob = job(\"cleanup\", async () => {\r\n * await db.deleteExpiredTokens();\r\n * }).daily().at(\"03:00\");\r\n * ```\r\n */\r\nexport function job(name: string, callback: JobCallback): Job {\r\n return new Job(name, callback);\r\n}\r\n","import { EventEmitter } from \"events\";\r\nimport { Job, JobCallback } from \"./job\";\r\nimport type { JobResult, SchedulerEvents } from \"./types\";\r\n\r\n/**\r\n * Type-safe event emitter interface for Scheduler events\r\n */\r\ninterface TypedEventEmitter<TEvents extends Record<string, unknown[]>> {\r\n on<K extends keyof TEvents>(event: K, listener: (...args: TEvents[K]) => void): this;\r\n once<K extends keyof TEvents>(event: K, listener: (...args: TEvents[K]) => void): this;\r\n off<K extends keyof TEvents>(event: K, listener: (...args: TEvents[K]) => void): this;\r\n emit<K extends keyof TEvents>(event: K, ...args: TEvents[K]): boolean;\r\n}\r\n\r\n/**\r\n * Scheduler class manages and executes scheduled jobs.\r\n *\r\n * Features:\r\n * - Event-based observability\r\n * - Parallel or sequential job execution\r\n * - Drift compensation for accurate timing\r\n * - Graceful shutdown with job draining\r\n *\r\n * @example\r\n * ```typescript\r\n * const scheduler = new Scheduler();\r\n *\r\n * scheduler.on('job:error', (jobName, error) => {\r\n * logger.error(`Job ${jobName} failed:`, error);\r\n * });\r\n *\r\n * scheduler\r\n * .addJob(cleanupJob)\r\n * .addJob(reportJob)\r\n * .runInParallel(true)\r\n * .start();\r\n *\r\n * // Graceful shutdown\r\n * process.on('SIGTERM', () => scheduler.shutdown());\r\n * ```\r\n */\r\nexport class Scheduler\r\n extends (EventEmitter as new () => TypedEventEmitter<SchedulerEvents>)\r\n implements TypedEventEmitter<SchedulerEvents>\r\n{\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Private Properties\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * List of registered jobs\r\n */\r\n private _jobs: Job[] = [];\r\n\r\n /**\r\n * Reference to the current timeout for stopping\r\n */\r\n private _timeoutId: NodeJS.Timeout | null = null;\r\n\r\n /**\r\n * Tick interval in milliseconds (how often to check for due jobs)\r\n */\r\n private _tickInterval = 1000;\r\n\r\n /**\r\n * Whether to run due jobs in parallel\r\n */\r\n private _runInParallel = false;\r\n\r\n /**\r\n * Maximum concurrent jobs when running in parallel\r\n */\r\n private _maxConcurrency = 10;\r\n\r\n /**\r\n * Flag indicating scheduler is shutting down\r\n */\r\n private _isShuttingDown = false;\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Public Getters\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Returns true if the scheduler is currently running\r\n */\r\n public get isRunning(): boolean {\r\n return this._timeoutId !== null;\r\n }\r\n\r\n /**\r\n * Returns the number of registered jobs\r\n */\r\n public get jobCount(): number {\r\n return this._jobs.length;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Configuration Methods (Fluent API)\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Add a job to the scheduler\r\n *\r\n * @param job - Job instance to schedule\r\n * @returns this for chaining\r\n */\r\n public addJob(job: Job): this {\r\n this._jobs.push(job);\r\n return this;\r\n }\r\n\r\n /**\r\n * Alias to create a new job directly and store it\r\n */\r\n public newJob(name: string, jobCallback: JobCallback) {\r\n const job = new Job(name, jobCallback);\r\n this.addJob(job);\r\n return job;\r\n }\r\n\r\n /**\r\n * Add multiple jobs to the scheduler\r\n *\r\n * @param jobs - Array of Job instances\r\n * @returns this for chaining\r\n */\r\n public addJobs(jobs: Job[]): this {\r\n this._jobs.push(...jobs);\r\n return this;\r\n }\r\n\r\n /**\r\n * Remove a job from the scheduler by name\r\n *\r\n * @param jobName - Name of the job to remove\r\n * @returns true if job was found and removed\r\n */\r\n public removeJob(jobName: string): boolean {\r\n const index = this._jobs.findIndex((j) => j.name === jobName);\r\n if (index !== -1) {\r\n this._jobs.splice(index, 1);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Get a job by name\r\n *\r\n * @param jobName - Name of the job to find\r\n * @returns Job instance or undefined\r\n */\r\n public getJob(jobName: string): Job | undefined {\r\n return this._jobs.find((j) => j.name === jobName);\r\n }\r\n\r\n /**\r\n * Get all registered jobs\r\n *\r\n * @returns Array of registered jobs (readonly)\r\n */\r\n public list(): readonly Job[] {\r\n return this._jobs;\r\n }\r\n\r\n /**\r\n * Set the tick interval (how often to check for due jobs)\r\n *\r\n * @param ms - Interval in milliseconds (minimum 100ms)\r\n * @returns this for chaining\r\n */\r\n public runEvery(ms: number): this {\r\n if (ms < 100) {\r\n throw new Error(\"Tick interval must be at least 100ms\");\r\n }\r\n this._tickInterval = ms;\r\n return this;\r\n }\r\n\r\n /**\r\n * Configure whether jobs should run in parallel\r\n *\r\n * @param parallel - Enable parallel execution\r\n * @param maxConcurrency - Maximum concurrent jobs (default: 10)\r\n * @returns this for chaining\r\n */\r\n public runInParallel(parallel: boolean, maxConcurrency = 10): this {\r\n this._runInParallel = parallel;\r\n this._maxConcurrency = maxConcurrency;\r\n return this;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Lifecycle Methods\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Start the scheduler\r\n *\r\n * @throws Error if scheduler is already running\r\n */\r\n public start(): void {\r\n if (this.isRunning) {\r\n throw new Error(\"Scheduler is already running.\");\r\n }\r\n\r\n if (this._jobs.length === 0) {\r\n throw new Error(\"Cannot start scheduler with no jobs.\");\r\n }\r\n\r\n // Prepare all jobs (calculate initial next run times)\r\n for (const job of this._jobs) {\r\n job.prepare();\r\n }\r\n\r\n this._isShuttingDown = false;\r\n this._scheduleTick();\r\n\r\n this.emit(\"scheduler:started\");\r\n }\r\n\r\n /**\r\n * Stop the scheduler immediately\r\n *\r\n * Note: This does not wait for running jobs to complete.\r\n * Use shutdown() for graceful termination.\r\n */\r\n public stop(): void {\r\n if (this._timeoutId) {\r\n clearTimeout(this._timeoutId);\r\n this._timeoutId = null;\r\n }\r\n\r\n this.emit(\"scheduler:stopped\");\r\n }\r\n\r\n /**\r\n * Gracefully shutdown the scheduler\r\n *\r\n * Stops scheduling new jobs and waits for currently running jobs to complete.\r\n *\r\n * @param timeout - Maximum time to wait for jobs (default: 30000ms)\r\n * @returns Promise that resolves when shutdown is complete\r\n */\r\n public async shutdown(timeout = 30000): Promise<void> {\r\n this._isShuttingDown = true;\r\n this.stop();\r\n\r\n // Get all currently running jobs\r\n const runningJobs = this._jobs.filter((j) => j.isRunning);\r\n\r\n if (runningJobs.length > 0) {\r\n // Wait for jobs to complete or timeout\r\n await Promise.race([\r\n Promise.all(runningJobs.map((j) => j.waitForCompletion())),\r\n new Promise<void>((resolve) => setTimeout(resolve, timeout)),\r\n ]);\r\n }\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Private Methods\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Schedule the next tick\r\n */\r\n private _scheduleTick(): void {\r\n if (this._isShuttingDown) return;\r\n\r\n const startTime = Date.now();\r\n\r\n // Use setImmediate for first tick to allow event handlers to be registered\r\n this._timeoutId = setTimeout(async () => {\r\n await this._tick();\r\n\r\n // Calculate time spent and adjust next tick for drift compensation\r\n const elapsed = Date.now() - startTime;\r\n const nextTick = Math.max(this._tickInterval - elapsed, 0);\r\n\r\n this._scheduleTick();\r\n }, this._tickInterval);\r\n }\r\n\r\n /**\r\n * Execute a scheduler tick - check and run due jobs\r\n */\r\n private async _tick(): Promise<void> {\r\n this.emit(\"scheduler:tick\", new Date());\r\n\r\n // Find jobs that should run\r\n const dueJobs = this._jobs.filter((job) => {\r\n if (!job.shouldRun()) return false;\r\n\r\n // Skip if overlap prevention is enabled and job is running\r\n if (job.isRunning) {\r\n this.emit(\"job:skip\", job.name, \"Job is already running\");\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n\r\n if (dueJobs.length === 0) return;\r\n\r\n if (this._runInParallel) {\r\n await this._runJobsInParallel(dueJobs);\r\n } else {\r\n await this._runJobsSequentially(dueJobs);\r\n }\r\n }\r\n\r\n /**\r\n * Run jobs sequentially\r\n */\r\n private async _runJobsSequentially(jobs: Job[]): Promise<void> {\r\n for (const job of jobs) {\r\n if (this._isShuttingDown) break;\r\n await this._runJob(job);\r\n }\r\n }\r\n\r\n /**\r\n * Run jobs in parallel with concurrency limit\r\n */\r\n private async _runJobsInParallel(jobs: Job[]): Promise<void> {\r\n // Simple batching for concurrency control\r\n const batches: Job[][] = [];\r\n\r\n for (let i = 0; i < jobs.length; i += this._maxConcurrency) {\r\n batches.push(jobs.slice(i, i + this._maxConcurrency));\r\n }\r\n\r\n for (const batch of batches) {\r\n if (this._isShuttingDown) break;\r\n await Promise.allSettled(batch.map((job) => this._runJob(job)));\r\n }\r\n }\r\n\r\n /**\r\n * Run a single job and emit events\r\n */\r\n private async _runJob(job: Job): Promise<JobResult> {\r\n this.emit(\"job:start\", job.name);\r\n\r\n const result = await job.run();\r\n\r\n if (result.success) {\r\n this.emit(\"job:complete\", job.name, result);\r\n } else {\r\n this.emit(\"job:error\", job.name, result.error);\r\n }\r\n\r\n return result;\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────────\r\n// Default Export\r\n// ─────────────────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Default scheduler instance for simple use cases\r\n *\r\n * @example\r\n * ```typescript\r\n * import { scheduler, job } from \"@warlock.js/scheduler\";\r\n *\r\n * scheduler.addJob(job(\"cleanup\", cleanupFn).daily());\r\n * scheduler.start();\r\n * ```\r\n */\r\nexport const scheduler = new Scheduler();\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../warlock.js/scheduler/src/cron-parser.ts","../../../../../../../warlock.js/scheduler/src/job.ts","../../../../../../../warlock.js/scheduler/src/scheduler.ts"],"names":["dayjs","job"],"mappings":"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","file":"index.js","sourcesContent":["import dayjs, { type Dayjs } from \"dayjs\";\n\n/**\n * Parsed cron expression fields\n */\nexport type CronFields = {\n /** Minutes (0-59) */\n minutes: number[];\n /** Hours (0-23) */\n hours: number[];\n /** Days of month (1-31) */\n daysOfMonth: number[];\n /** Months (1-12) */\n months: number[];\n /** Days of week (0-6, Sunday = 0) */\n daysOfWeek: number[];\n};\n\n/**\n * Cron expression parser\n *\n * Supports standard 5-field cron expressions:\n * ```\n * ┌───────────── minute (0-59)\n * │ ┌───────────── hour (0-23)\n * │ │ ┌───────────── day of month (1-31)\n * │ │ │ ┌───────────── month (1-12)\n * │ │ │ │ ┌───────────── day of week (0-6, Sunday = 0)\n * │ │ │ │ │\n * * * * * *\n * ```\n *\n * Supports:\n * - `*` - any value\n * - `5` - specific value\n * - `1,3,5` - list of values\n * - `1-5` - range of values\n * - `* /5` - step values (every 5)\n * - `1-10/2` - range with step\n *\n * @example\n * ```typescript\n * const parser = new CronParser(\"0 9 * * 1-5\"); // 9 AM weekdays\n * const nextRun = parser.nextRun();\n * ```\n */\nexport class CronParser {\n private readonly _fields: CronFields;\n\n /**\n * Creates a new CronParser instance\n *\n * @param expression - Standard 5-field cron expression\n * @throws Error if expression is invalid\n */\n public constructor(private readonly _expression: string) {\n this._fields = this._parse(_expression);\n }\n\n /**\n * Get the parsed cron fields\n */\n public get fields(): Readonly<CronFields> {\n return this._fields;\n }\n\n /**\n * Get the original expression\n */\n public get expression(): string {\n return this._expression;\n }\n\n /**\n * Calculate the next run time from a given date\n *\n * @param from - Starting date (defaults to now)\n * @returns Next run time as Dayjs\n */\n public nextRun(from: Dayjs = dayjs()): Dayjs {\n let date = from.add(1, \"minute\").second(0).millisecond(0);\n\n // Maximum iterations to prevent infinite loops\n const maxIterations = 366 * 24 * 60; // 1 year of minutes\n let iterations = 0;\n\n while (iterations < maxIterations) {\n iterations++;\n\n // Check month\n if (!this._fields.months.includes(date.month() + 1)) {\n date = date.add(1, \"month\").date(1).hour(0).minute(0);\n continue;\n }\n\n // Check day of month\n if (!this._fields.daysOfMonth.includes(date.date())) {\n date = date.add(1, \"day\").hour(0).minute(0);\n continue;\n }\n\n // Check day of week\n if (!this._fields.daysOfWeek.includes(date.day())) {\n date = date.add(1, \"day\").hour(0).minute(0);\n continue;\n }\n\n // Check hour\n if (!this._fields.hours.includes(date.hour())) {\n date = date.add(1, \"hour\").minute(0);\n continue;\n }\n\n // Check minute\n if (!this._fields.minutes.includes(date.minute())) {\n date = date.add(1, \"minute\");\n continue;\n }\n\n // All fields match!\n return date;\n }\n\n throw new Error(`Could not find next run time for cron expression: ${this._expression}`);\n }\n\n /**\n * Check if a given date matches the cron expression\n *\n * @param date - Date to check\n * @returns true if the date matches\n */\n public matches(date: Dayjs): boolean {\n return (\n this._fields.minutes.includes(date.minute()) &&\n this._fields.hours.includes(date.hour()) &&\n this._fields.daysOfMonth.includes(date.date()) &&\n this._fields.months.includes(date.month() + 1) &&\n this._fields.daysOfWeek.includes(date.day())\n );\n }\n\n /**\n * Parse a cron expression into fields\n */\n private _parse(expression: string): CronFields {\n const parts = expression.trim().split(/\\s+/);\n\n if (parts.length !== 5) {\n throw new Error(\n `Invalid cron expression: \"${expression}\". Expected 5 fields (minute hour day month weekday).`,\n );\n }\n\n const [minute, hour, dayOfMonth, month, dayOfWeek] = parts;\n\n return {\n minutes: this._parseField(minute, 0, 59),\n hours: this._parseField(hour, 0, 23),\n daysOfMonth: this._parseField(dayOfMonth, 1, 31),\n months: this._parseField(month, 1, 12),\n daysOfWeek: this._parseField(dayOfWeek, 0, 6),\n };\n }\n\n /**\n * Parse a single cron field\n *\n * @param field - Field value (e.g., \"*\", \"5\", \"1-5\", \"* /2\", \"1,3,5\")\n * @param min - Minimum allowed value\n * @param max - Maximum allowed value\n * @returns Array of matching values\n */\n private _parseField(field: string, min: number, max: number): number[] {\n const values = new Set<number>();\n\n // Handle lists (e.g., \"1,3,5\")\n const parts = field.split(\",\");\n\n for (const part of parts) {\n // Handle step values (e.g., \"*/5\" or \"1-10/2\")\n const [range, stepStr] = part.split(\"/\");\n const step = stepStr ? parseInt(stepStr, 10) : 1;\n\n if (isNaN(step) || step < 1) {\n throw new Error(`Invalid step value in cron field: \"${field}\"`);\n }\n\n let rangeStart: number;\n let rangeEnd: number;\n\n if (range === \"*\") {\n // Wildcard - all values\n rangeStart = min;\n rangeEnd = max;\n } else if (range.includes(\"-\")) {\n // Range (e.g., \"1-5\")\n const [startStr, endStr] = range.split(\"-\");\n rangeStart = parseInt(startStr, 10);\n rangeEnd = parseInt(endStr, 10);\n\n if (isNaN(rangeStart) || isNaN(rangeEnd)) {\n throw new Error(`Invalid range in cron field: \"${field}\"`);\n }\n\n if (rangeStart < min || rangeEnd > max || rangeStart > rangeEnd) {\n throw new Error(`Range out of bounds in cron field: \"${field}\" (valid: ${min}-${max})`);\n }\n } else {\n // Single value\n const value = parseInt(range, 10);\n\n if (isNaN(value)) {\n throw new Error(`Invalid value in cron field: \"${field}\"`);\n }\n\n if (value < min || value > max) {\n throw new Error(`Value out of bounds in cron field: \"${field}\" (valid: ${min}-${max})`);\n }\n\n rangeStart = value;\n rangeEnd = value;\n }\n\n // Add values with step\n for (let i = rangeStart; i <= rangeEnd; i += step) {\n values.add(i);\n }\n }\n\n return Array.from(values).sort((a, b) => a - b);\n }\n}\n\n/**\n * Parse a cron expression string\n *\n * @param expression - Cron expression (5 fields)\n * @returns CronParser instance\n */\nexport function parseCron(expression: string): CronParser {\n return new CronParser(expression);\n}\n","import dayjs, { type Dayjs } from \"dayjs\";\r\nimport timezone from \"dayjs/plugin/timezone.js\";\r\nimport utc from \"dayjs/plugin/utc.js\";\r\nimport { CronParser } from \"./cron-parser\";\r\nimport type { Day, JobIntervals, JobResult, RetryConfig, TimeType } from \"./types\";\r\n\r\n// Enable timezone support\r\ndayjs.extend(utc);\r\ndayjs.extend(timezone);\r\n\r\nexport type JobCallback = (job: Job) => Promise<any>;\r\n\r\n/**\r\n * Days of week mapping (lowercase for consistency with Day type)\r\n */\r\nconst DAYS_OF_WEEK: Day[] = [\r\n \"sunday\",\r\n \"monday\",\r\n \"tuesday\",\r\n \"wednesday\",\r\n \"thursday\",\r\n \"friday\",\r\n \"saturday\",\r\n];\r\n\r\n/**\r\n * Job class represents a scheduled task with configurable timing and execution options.\r\n *\r\n * @example\r\n * ```typescript\r\n * const job = new Job(\"cleanup\", async () => {\r\n * await cleanupOldFiles();\r\n * })\r\n * .everyDay()\r\n * .at(\"03:00\")\r\n * .inTimezone(\"America/New_York\")\r\n * .preventOverlap()\r\n * .retry(3, 1000);\r\n * ```\r\n */\r\nexport class Job {\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Private Properties\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Interval configuration for scheduling\r\n */\r\n private _intervals: JobIntervals = {};\r\n\r\n /**\r\n * Last execution timestamp\r\n */\r\n private _lastRun: Dayjs | null = null;\r\n\r\n /**\r\n * Whether the job is currently executing\r\n */\r\n private _isRunning = false;\r\n\r\n /**\r\n * Skip execution if job is already running\r\n */\r\n private _skipIfRunning = false;\r\n\r\n /**\r\n * Retry configuration\r\n */\r\n private _retryConfig: RetryConfig | null = null;\r\n\r\n /**\r\n * Timezone for scheduling (defaults to system timezone)\r\n */\r\n private _timezone: string | null = null;\r\n\r\n /**\r\n * Cron expression parser (mutually exclusive with interval config)\r\n */\r\n private _cronParser: CronParser | null = null;\r\n\r\n /**\r\n * Promise resolver for completion waiting\r\n */\r\n private _completionResolver: (() => void) | null = null;\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Public Properties\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Next scheduled execution time\r\n */\r\n public nextRun: Dayjs | null = null;\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Constructor\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Creates a new Job instance\r\n *\r\n * @param name - Unique identifier for the job\r\n * @param callback - Function to execute when the job runs\r\n */\r\n public constructor(\r\n public readonly name: string,\r\n private readonly _callback: JobCallback,\r\n ) {}\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Public Getters\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Returns true if the job is currently executing\r\n */\r\n public get isRunning(): boolean {\r\n return this._isRunning;\r\n }\r\n\r\n /**\r\n * Returns the last execution timestamp\r\n */\r\n public get lastRun(): Dayjs | null {\r\n return this._lastRun;\r\n }\r\n\r\n /**\r\n * Returns the current interval configuration (readonly)\r\n */\r\n public get intervals(): Readonly<JobIntervals> {\r\n return this._intervals;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Interval Configuration Methods (Fluent API)\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Set a custom interval for job execution\r\n *\r\n * @param value - Number of time units\r\n * @param timeType - Type of time unit\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.every(5, \"minute\"); // Run every 5 minutes\r\n * job.every(2, \"hour\"); // Run every 2 hours\r\n * ```\r\n */\r\n public every(value: number, timeType: TimeType): this {\r\n this._intervals.every = { type: timeType, value };\r\n return this;\r\n }\r\n\r\n /**\r\n * Run job every second (use with caution - high frequency)\r\n */\r\n public everySecond(): this {\r\n return this.every(1, \"second\");\r\n }\r\n\r\n /**\r\n * Run job every specified number of seconds\r\n */\r\n public everySeconds(seconds: number): this {\r\n return this.every(seconds, \"second\");\r\n }\r\n\r\n /**\r\n * Run job every minute\r\n */\r\n public everyMinute(): this {\r\n return this.every(1, \"minute\");\r\n }\r\n\r\n /**\r\n * Run job every specified number of minutes\r\n */\r\n public everyMinutes(minutes: number): this {\r\n return this.every(minutes, \"minute\");\r\n }\r\n\r\n /**\r\n * Run job every hour\r\n */\r\n public everyHour(): this {\r\n return this.every(1, \"hour\");\r\n }\r\n\r\n /**\r\n * Run job every specified number of hours\r\n */\r\n public everyHours(hours: number): this {\r\n return this.every(hours, \"hour\");\r\n }\r\n\r\n /**\r\n * Run job every day at midnight\r\n */\r\n public everyDay(): this {\r\n return this.every(1, \"day\");\r\n }\r\n\r\n /**\r\n * Alias for everyDay()\r\n */\r\n public daily(): this {\r\n return this.everyDay();\r\n }\r\n\r\n /**\r\n * Run job twice a day (every 12 hours)\r\n */\r\n public twiceDaily(): this {\r\n return this.every(12, \"hour\");\r\n }\r\n\r\n /**\r\n * Run job every week\r\n */\r\n public everyWeek(): this {\r\n return this.every(1, \"week\");\r\n }\r\n\r\n /**\r\n * Alias for everyWeek()\r\n */\r\n public weekly(): this {\r\n return this.everyWeek();\r\n }\r\n\r\n /**\r\n * Run job every month\r\n */\r\n public everyMonth(): this {\r\n return this.every(1, \"month\");\r\n }\r\n\r\n /**\r\n * Alias for everyMonth()\r\n */\r\n public monthly(): this {\r\n return this.everyMonth();\r\n }\r\n\r\n /**\r\n * Run job every year\r\n */\r\n public everyYear(): this {\r\n return this.every(1, \"year\");\r\n }\r\n\r\n /**\r\n * Alias for everyYear()\r\n */\r\n public yearly(): this {\r\n return this.everyYear();\r\n }\r\n\r\n /**\r\n * Alias for everyMinute() - job runs continuously every minute\r\n */\r\n public always(): this {\r\n return this.everyMinute();\r\n }\r\n\r\n /**\r\n * Schedule job using a cron expression\r\n *\r\n * Supports standard 5-field cron syntax:\r\n * ```\r\n * ┌───────────── minute (0-59)\r\n * │ ┌───────────── hour (0-23)\r\n * │ │ ┌───────────── day of month (1-31)\r\n * │ │ │ ┌───────────── month (1-12)\r\n * │ │ │ │ ┌───────────── day of week (0-6, Sunday = 0)\r\n * │ │ │ │ │\r\n * * * * * *\r\n * ```\r\n *\r\n * Supports:\r\n * - '*' - any value\r\n * - '5' - specific value\r\n * - '1,3,5' - list of values\r\n * - '1-5' - range of values\r\n * - 'x/5' - step values (every 5)\r\n * - '1-10/2' - range with step\r\n *\r\n * @param expression - Standard 5-field cron expression\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.cron(\"0 9 * * 1-5\"); // 9 AM weekdays\r\n * job.cron(\"x/5 * * * *\"); // Every 5 minutes\r\n * job.cron(\"0 0 1 * *\"); // First day of month at midnight\r\n * job.cron(\"0 x/2 * * *\"); // Every 2 hours\r\n * ```\r\n */\r\n public cron(expression: string): this {\r\n this._cronParser = new CronParser(expression);\r\n // Clear interval config since cron takes precedence\r\n this._intervals = {};\r\n return this;\r\n }\r\n\r\n /**\r\n * Get the cron expression if one is set\r\n */\r\n public get cronExpression(): string | null {\r\n return this._cronParser?.expression ?? null;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Day & Time Configuration Methods\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Schedule job on a specific day\r\n *\r\n * @param day - Day of week (string) or day of month (number 1-31)\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.on(\"monday\"); // Run on Mondays\r\n * job.on(15); // Run on the 15th of each month\r\n * ```\r\n */\r\n public on(day: Day | number): this {\r\n if (typeof day === \"number\" && (day < 1 || day > 31)) {\r\n throw new Error(\"Invalid day of the month. Must be between 1 and 31.\");\r\n }\r\n\r\n this._intervals.day = day;\r\n return this;\r\n }\r\n\r\n /**\r\n * Schedule job at a specific time\r\n *\r\n * @param time - Time in HH:mm or HH:mm:ss format\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.daily().at(\"09:00\"); // Run daily at 9 AM\r\n * job.weekly().at(\"14:30\"); // Run weekly at 2:30 PM\r\n * ```\r\n */\r\n public at(time: string): this {\r\n // Validate time format\r\n if (!/^\\d{1,2}:\\d{2}(:\\d{2})?$/.test(time)) {\r\n throw new Error(\"Invalid time format. Use HH:mm or HH:mm:ss.\");\r\n }\r\n\r\n this._intervals.time = time;\r\n return this;\r\n }\r\n\r\n /**\r\n * Run task at the beginning of the specified time period\r\n *\r\n * @param type - Time type (day, month, year)\r\n */\r\n public beginOf(type: TimeType): this {\r\n const time = \"00:00\";\r\n\r\n switch (type) {\r\n case \"day\":\r\n break;\r\n case \"month\":\r\n this.on(1);\r\n break;\r\n case \"year\":\r\n this.on(1);\r\n this.every(1, \"year\");\r\n break;\r\n default:\r\n throw new Error(`Unsupported type for beginOf: ${type}`);\r\n }\r\n\r\n return this.at(time);\r\n }\r\n\r\n /**\r\n * Run task at the end of the specified time period\r\n *\r\n * @param type - Time type (day, month, year)\r\n */\r\n public endOf(type: TimeType): this {\r\n const now = this._now();\r\n const time = \"23:59\";\r\n\r\n switch (type) {\r\n case \"day\":\r\n break;\r\n case \"month\":\r\n this.on(now.endOf(\"month\").date());\r\n break;\r\n case \"year\":\r\n this.on(31);\r\n this.every(1, \"year\");\r\n break;\r\n default:\r\n throw new Error(`Unsupported type for endOf: ${type}`);\r\n }\r\n\r\n return this.at(time);\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Timezone Configuration\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Set the timezone for this job's scheduling\r\n *\r\n * @param tz - IANA timezone string (e.g., \"America/New_York\", \"Europe/London\")\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.daily().at(\"09:00\").inTimezone(\"America/New_York\");\r\n * ```\r\n */\r\n public inTimezone(tz: string): this {\r\n this._timezone = tz;\r\n return this;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Execution Options\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Prevent overlapping executions of this job\r\n *\r\n * When enabled, if the job is already running when it's scheduled to run again,\r\n * the new execution will be skipped.\r\n *\r\n * @param skip - Whether to skip if already running (default: true)\r\n * @returns this for chaining\r\n */\r\n public preventOverlap(skip = true): this {\r\n this._skipIfRunning = skip;\r\n return this;\r\n }\r\n\r\n /**\r\n * Configure automatic retry on failure\r\n *\r\n * @param maxRetries - Maximum number of retry attempts\r\n * @param delay - Delay between retries in milliseconds\r\n * @param backoffMultiplier - Optional multiplier for exponential backoff\r\n * @returns this for chaining\r\n *\r\n * @example\r\n * ```typescript\r\n * job.retry(3, 1000); // Retry 3 times with 1s delay\r\n * job.retry(5, 1000, 2); // Exponential backoff: 1s, 2s, 4s, 8s, 16s\r\n * ```\r\n */\r\n public retry(maxRetries: number, delay = 1000, backoffMultiplier?: number): this {\r\n this._retryConfig = {\r\n maxRetries,\r\n delay,\r\n backoffMultiplier,\r\n };\r\n return this;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Execution Control\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Terminate the job and clear all scheduling data\r\n */\r\n public terminate(): this {\r\n this._intervals = {};\r\n this.nextRun = null;\r\n this._lastRun = null;\r\n this._isRunning = false;\r\n return this;\r\n }\r\n\r\n /**\r\n * Prepare the job by calculating the next run time\r\n * Called by the scheduler when starting\r\n */\r\n public prepare(): void {\r\n this._determineNextRun();\r\n }\r\n\r\n /**\r\n * Determine if the job should run now\r\n *\r\n * @returns true if the job should execute\r\n */\r\n public shouldRun(): boolean {\r\n // Skip if already running and overlap prevention is enabled\r\n if (this._skipIfRunning && this._isRunning) {\r\n return false;\r\n }\r\n\r\n return this.nextRun !== null && this._now().isAfter(this.nextRun);\r\n }\r\n\r\n /**\r\n * Execute the job\r\n *\r\n * @returns Promise resolving to the job result\r\n */\r\n public async run(): Promise<JobResult> {\r\n const startTime = Date.now();\r\n let retries = 0;\r\n\r\n this._isRunning = true;\r\n\r\n try {\r\n const result = await this._executeWithRetry();\r\n this._lastRun = this._now();\r\n this._determineNextRun();\r\n\r\n return {\r\n success: true,\r\n duration: Date.now() - startTime,\r\n retries: result.retries || 0,\r\n };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n duration: Date.now() - startTime,\r\n error,\r\n retries: this._retryConfig?.maxRetries ?? 0,\r\n };\r\n } finally {\r\n this._isRunning = false;\r\n\r\n // Resolve any waiting completion promises\r\n if (this._completionResolver) {\r\n this._completionResolver();\r\n this._completionResolver = null;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Wait for the job to complete\r\n * Useful for graceful shutdown\r\n *\r\n * @returns Promise that resolves when the job completes\r\n */\r\n public waitForCompletion(): Promise<void> {\r\n if (!this._isRunning) {\r\n return Promise.resolve();\r\n }\r\n\r\n return new Promise((resolve) => {\r\n this._completionResolver = resolve;\r\n });\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Private Methods\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Get current time, respecting timezone if set\r\n */\r\n private _now(): Dayjs {\r\n return this._timezone ? dayjs().tz(this._timezone) : dayjs();\r\n }\r\n\r\n /**\r\n * Execute the callback with retry logic\r\n */\r\n private async _executeWithRetry(): Promise<{ retries: number }> {\r\n let lastError: unknown;\r\n let attempts = 0;\r\n const maxAttempts = (this._retryConfig?.maxRetries ?? 0) + 1;\r\n\r\n while (attempts < maxAttempts) {\r\n try {\r\n await this._callback(this);\r\n return { retries: attempts };\r\n } catch (error) {\r\n lastError = error;\r\n attempts++;\r\n\r\n if (attempts < maxAttempts && this._retryConfig) {\r\n const delay = this._calculateRetryDelay(attempts);\r\n await this._sleep(delay);\r\n }\r\n }\r\n }\r\n\r\n throw lastError;\r\n }\r\n\r\n /**\r\n * Calculate retry delay with optional exponential backoff\r\n */\r\n private _calculateRetryDelay(attempt: number): number {\r\n if (!this._retryConfig) return 0;\r\n\r\n const { delay, backoffMultiplier } = this._retryConfig;\r\n\r\n if (backoffMultiplier) {\r\n return delay * Math.pow(backoffMultiplier, attempt - 1);\r\n }\r\n\r\n return delay;\r\n }\r\n\r\n /**\r\n * Sleep for specified milliseconds\r\n */\r\n private _sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n }\r\n\r\n /**\r\n * Calculate the next run time based on interval or cron configuration\r\n */\r\n private _determineNextRun(): void {\r\n // If using cron expression, delegate to cron parser\r\n if (this._cronParser) {\r\n const now = this._now();\r\n this.nextRun = this._cronParser.nextRun(now);\r\n return;\r\n }\r\n\r\n // Otherwise use interval-based scheduling\r\n let date = this._lastRun ? this._lastRun.add(1, \"second\") : this._now();\r\n\r\n // Apply interval\r\n if (this._intervals.every?.value && this._intervals.every?.type) {\r\n date = date.add(this._intervals.every.value, this._intervals.every.type);\r\n }\r\n\r\n // Apply day constraint\r\n if (this._intervals.day !== undefined) {\r\n if (typeof this._intervals.day === \"number\") {\r\n date = date.date(this._intervals.day);\r\n } else {\r\n const targetDay = DAYS_OF_WEEK.indexOf(this._intervals.day);\r\n if (targetDay !== -1) {\r\n date = date.day(targetDay);\r\n }\r\n }\r\n }\r\n\r\n // Apply time constraint\r\n if (this._intervals.time) {\r\n const parts = this._intervals.time.split(\":\").map(Number);\r\n const [hour, minute, second = 0] = parts;\r\n date = date.hour(hour).minute(minute).second(second).millisecond(0);\r\n }\r\n\r\n // Ensure the next run is in the future\r\n while (date.isBefore(this._now())) {\r\n if (this._intervals.every?.value && this._intervals.every?.type) {\r\n date = date.add(this._intervals.every.value, this._intervals.every.type);\r\n } else {\r\n // Default to adding one day if there's no specific interval defined\r\n date = date.add(1, \"day\");\r\n }\r\n }\r\n\r\n this.nextRun = date;\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────────\r\n// Factory Function\r\n// ─────────────────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Factory function to create a new Job instance\r\n *\r\n * @param name - Unique identifier for the job\r\n * @param callback - Function to execute when the job runs\r\n * @returns New Job instance\r\n *\r\n * @example\r\n * ```typescript\r\n * const cleanupJob = job(\"cleanup\", async () => {\r\n * await db.deleteExpiredTokens();\r\n * }).daily().at(\"03:00\");\r\n * ```\r\n */\r\nexport function job(name: string, callback: JobCallback): Job {\r\n return new Job(name, callback);\r\n}\r\n","import { EventEmitter } from \"events\";\r\nimport { Job, JobCallback } from \"./job\";\r\nimport type { JobResult, SchedulerEvents } from \"./types\";\r\n\r\n/**\r\n * Type-safe event emitter interface for Scheduler events\r\n */\r\ninterface TypedEventEmitter<TEvents extends Record<string, unknown[]>> {\r\n on<K extends keyof TEvents>(event: K, listener: (...args: TEvents[K]) => void): this;\r\n once<K extends keyof TEvents>(event: K, listener: (...args: TEvents[K]) => void): this;\r\n off<K extends keyof TEvents>(event: K, listener: (...args: TEvents[K]) => void): this;\r\n emit<K extends keyof TEvents>(event: K, ...args: TEvents[K]): boolean;\r\n}\r\n\r\n/**\r\n * Scheduler class manages and executes scheduled jobs.\r\n *\r\n * Features:\r\n * - Event-based observability\r\n * - Parallel or sequential job execution\r\n * - Drift compensation for accurate timing\r\n * - Graceful shutdown with job draining\r\n *\r\n * @example\r\n * ```typescript\r\n * const scheduler = new Scheduler();\r\n *\r\n * scheduler.on('job:error', (jobName, error) => {\r\n * logger.error(`Job ${jobName} failed:`, error);\r\n * });\r\n *\r\n * scheduler\r\n * .addJob(cleanupJob)\r\n * .addJob(reportJob)\r\n * .runInParallel(true)\r\n * .start();\r\n *\r\n * // Graceful shutdown\r\n * process.on('SIGTERM', () => scheduler.shutdown());\r\n * ```\r\n */\r\nexport class Scheduler\r\n extends (EventEmitter as new () => TypedEventEmitter<SchedulerEvents>)\r\n implements TypedEventEmitter<SchedulerEvents>\r\n{\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Private Properties\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * List of registered jobs\r\n */\r\n private _jobs: Job[] = [];\r\n\r\n /**\r\n * Reference to the current timeout for stopping\r\n */\r\n private _timeoutId: NodeJS.Timeout | null = null;\r\n\r\n /**\r\n * Tick interval in milliseconds (how often to check for due jobs)\r\n */\r\n private _tickInterval = 1000;\r\n\r\n /**\r\n * Whether to run due jobs in parallel\r\n */\r\n private _runInParallel = false;\r\n\r\n /**\r\n * Maximum concurrent jobs when running in parallel\r\n */\r\n private _maxConcurrency = 10;\r\n\r\n /**\r\n * Flag indicating scheduler is shutting down\r\n */\r\n private _isShuttingDown = false;\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Public Getters\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Returns true if the scheduler is currently running\r\n */\r\n public get isRunning(): boolean {\r\n return this._timeoutId !== null;\r\n }\r\n\r\n /**\r\n * Returns the number of registered jobs\r\n */\r\n public get jobCount(): number {\r\n return this._jobs.length;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Configuration Methods (Fluent API)\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Add a job to the scheduler\r\n *\r\n * @param job - Job instance to schedule\r\n * @returns this for chaining\r\n */\r\n public addJob(job: Job): this {\r\n this._jobs.push(job);\r\n return this;\r\n }\r\n\r\n /**\r\n * Alias to create a new job directly and store it\r\n */\r\n public newJob(name: string, jobCallback: JobCallback) {\r\n const job = new Job(name, jobCallback);\r\n this.addJob(job);\r\n return job;\r\n }\r\n\r\n /**\r\n * Add multiple jobs to the scheduler\r\n *\r\n * @param jobs - Array of Job instances\r\n * @returns this for chaining\r\n */\r\n public addJobs(jobs: Job[]): this {\r\n this._jobs.push(...jobs);\r\n return this;\r\n }\r\n\r\n /**\r\n * Remove a job from the scheduler by name\r\n *\r\n * @param jobName - Name of the job to remove\r\n * @returns true if job was found and removed\r\n */\r\n public removeJob(jobName: string): boolean {\r\n const index = this._jobs.findIndex((j) => j.name === jobName);\r\n if (index !== -1) {\r\n this._jobs.splice(index, 1);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Get a job by name\r\n *\r\n * @param jobName - Name of the job to find\r\n * @returns Job instance or undefined\r\n */\r\n public getJob(jobName: string): Job | undefined {\r\n return this._jobs.find((j) => j.name === jobName);\r\n }\r\n\r\n /**\r\n * Get all registered jobs\r\n *\r\n * @returns Array of registered jobs (readonly)\r\n */\r\n public list(): readonly Job[] {\r\n return this._jobs;\r\n }\r\n\r\n /**\r\n * Set the tick interval (how often to check for due jobs)\r\n *\r\n * @param ms - Interval in milliseconds (minimum 100ms)\r\n * @returns this for chaining\r\n */\r\n public runEvery(ms: number): this {\r\n if (ms < 100) {\r\n throw new Error(\"Tick interval must be at least 100ms\");\r\n }\r\n this._tickInterval = ms;\r\n return this;\r\n }\r\n\r\n /**\r\n * Configure whether jobs should run in parallel\r\n *\r\n * @param parallel - Enable parallel execution\r\n * @param maxConcurrency - Maximum concurrent jobs (default: 10)\r\n * @returns this for chaining\r\n */\r\n public runInParallel(parallel: boolean, maxConcurrency = 10): this {\r\n this._runInParallel = parallel;\r\n this._maxConcurrency = maxConcurrency;\r\n return this;\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Lifecycle Methods\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Start the scheduler\r\n *\r\n * @throws Error if scheduler is already running\r\n */\r\n public start(): void {\r\n if (this.isRunning) {\r\n throw new Error(\"Scheduler is already running.\");\r\n }\r\n\r\n if (this._jobs.length === 0) {\r\n throw new Error(\"Cannot start scheduler with no jobs.\");\r\n }\r\n\r\n // Prepare all jobs (calculate initial next run times)\r\n for (const job of this._jobs) {\r\n job.prepare();\r\n }\r\n\r\n this._isShuttingDown = false;\r\n this._scheduleTick();\r\n\r\n this.emit(\"scheduler:started\");\r\n }\r\n\r\n /**\r\n * Stop the scheduler immediately\r\n *\r\n * Note: This does not wait for running jobs to complete.\r\n * Use shutdown() for graceful termination.\r\n */\r\n public stop(): void {\r\n if (this._timeoutId) {\r\n clearTimeout(this._timeoutId);\r\n this._timeoutId = null;\r\n }\r\n\r\n this.emit(\"scheduler:stopped\");\r\n }\r\n\r\n /**\r\n * Gracefully shutdown the scheduler\r\n *\r\n * Stops scheduling new jobs and waits for currently running jobs to complete.\r\n *\r\n * @param timeout - Maximum time to wait for jobs (default: 30000ms)\r\n * @returns Promise that resolves when shutdown is complete\r\n */\r\n public async shutdown(timeout = 30000): Promise<void> {\r\n this._isShuttingDown = true;\r\n this.stop();\r\n\r\n // Get all currently running jobs\r\n const runningJobs = this._jobs.filter((j) => j.isRunning);\r\n\r\n if (runningJobs.length > 0) {\r\n // Wait for jobs to complete or timeout\r\n await Promise.race([\r\n Promise.all(runningJobs.map((j) => j.waitForCompletion())),\r\n new Promise<void>((resolve) => setTimeout(resolve, timeout)),\r\n ]);\r\n }\r\n }\r\n\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n // Private Methods\r\n // ─────────────────────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Schedule the next tick\r\n */\r\n private _scheduleTick(): void {\r\n if (this._isShuttingDown) return;\r\n\r\n const startTime = Date.now();\r\n\r\n // Use setImmediate for first tick to allow event handlers to be registered\r\n this._timeoutId = setTimeout(async () => {\r\n await this._tick();\r\n\r\n // Calculate time spent and adjust next tick for drift compensation\r\n const elapsed = Date.now() - startTime;\r\n const nextTick = Math.max(this._tickInterval - elapsed, 0);\r\n\r\n this._scheduleTick();\r\n }, this._tickInterval);\r\n }\r\n\r\n /**\r\n * Execute a scheduler tick - check and run due jobs\r\n */\r\n private async _tick(): Promise<void> {\r\n this.emit(\"scheduler:tick\", new Date());\r\n\r\n // Find jobs that should run\r\n const dueJobs = this._jobs.filter((job) => {\r\n if (!job.shouldRun()) return false;\r\n\r\n // Skip if overlap prevention is enabled and job is running\r\n if (job.isRunning) {\r\n this.emit(\"job:skip\", job.name, \"Job is already running\");\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n\r\n if (dueJobs.length === 0) return;\r\n\r\n if (this._runInParallel) {\r\n await this._runJobsInParallel(dueJobs);\r\n } else {\r\n await this._runJobsSequentially(dueJobs);\r\n }\r\n }\r\n\r\n /**\r\n * Run jobs sequentially\r\n */\r\n private async _runJobsSequentially(jobs: Job[]): Promise<void> {\r\n for (const job of jobs) {\r\n if (this._isShuttingDown) break;\r\n await this._runJob(job);\r\n }\r\n }\r\n\r\n /**\r\n * Run jobs in parallel with concurrency limit\r\n */\r\n private async _runJobsInParallel(jobs: Job[]): Promise<void> {\r\n // Simple batching for concurrency control\r\n const batches: Job[][] = [];\r\n\r\n for (let i = 0; i < jobs.length; i += this._maxConcurrency) {\r\n batches.push(jobs.slice(i, i + this._maxConcurrency));\r\n }\r\n\r\n for (const batch of batches) {\r\n if (this._isShuttingDown) break;\r\n await Promise.allSettled(batch.map((job) => this._runJob(job)));\r\n }\r\n }\r\n\r\n /**\r\n * Run a single job and emit events\r\n */\r\n private async _runJob(job: Job): Promise<JobResult> {\r\n this.emit(\"job:start\", job.name);\r\n\r\n const result = await job.run();\r\n\r\n if (result.success) {\r\n this.emit(\"job:complete\", job.name, result);\r\n } else {\r\n this.emit(\"job:error\", job.name, result.error);\r\n }\r\n\r\n return result;\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────────\r\n// Default Export\r\n// ─────────────────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Default scheduler instance for simple use cases\r\n *\r\n * @example\r\n * ```typescript\r\n * import { scheduler, job } from \"@warlock.js/scheduler\";\r\n *\r\n * scheduler.addJob(job(\"cleanup\", cleanupFn).daily());\r\n * scheduler.start();\r\n * ```\r\n */\r\nexport const scheduler = new Scheduler();\r\n"]}
|