A cron-like and not-cron-like job scheduler for Node.js with flexible recurrence rules and time-based scheduling.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Flexible recurrence rule system for defining complex scheduling patterns with precise control over timing components in Node Schedule.
Create complex recurring schedules using rule-based specifications with fine-grained control over timing.
/**
* Create a recurrence rule for complex scheduling patterns
* @param {number|number[]|Range} [year] - Year specification
* @param {number|number[]|Range} [month] - Month specification (0-11, where 0=January)
* @param {number|number[]|Range} [date] - Day of month specification (1-31)
* @param {number|number[]|Range} [dayOfWeek] - Day of week specification (0-6, where 0=Sunday)
* @param {number|number[]|Range} [hour] - Hour specification (0-23)
* @param {number|number[]|Range} [minute] - Minute specification (0-59)
* @param {number|number[]|Range} [second] - Second specification (0-59, defaults to 0)
*/
function RecurrenceRule(year?, month?, date?, dayOfWeek?, hour?, minute?, second?);
class RecurrenceRule {
/** Year specification (4-digit year, null for any) */
year: number | number[] | Range | null;
/** Month specification (0-11, null for any) */
month: number | number[] | Range | null;
/** Day of month specification (1-31, null for any) */
date: number | number[] | Range | null;
/** Day of week specification (0-6, Sunday=0, null for any) */
dayOfWeek: number | number[] | Range | null;
/** Hour specification (0-23, null for any) */
hour: number | number[] | Range | null;
/** Minute specification (0-59, null for any) */
minute: number | number[] | Range | null;
/** Second specification (0-59, null for any) */
second: number | number[] | Range | null;
/** Whether this rule allows recurrence */
recurs: boolean;
/** Timezone identifier */
tz: string;
}Usage Examples:
const { RecurrenceRule, scheduleJob } = require('node-schedule');
// Every weekday at 9:30 AM
const rule1 = new RecurrenceRule();
rule1.dayOfWeek = [new Range(1, 5)]; // Monday to Friday
rule1.hour = 9;
rule1.minute = 30;
const job1 = scheduleJob(rule1, function() {
console.log('Weekday morning job');
});
// Every 15 minutes during business hours
const rule2 = new RecurrenceRule();
rule2.hour = [new Range(9, 17)]; // 9 AM to 5 PM
rule2.minute = [0, 15, 30, 45];
const job2 = scheduleJob(rule2, function() {
console.log('Business hours job');
});
// Last day of every month at midnight
const rule3 = new RecurrenceRule();
rule3.date = [28, 29, 30, 31]; // Will only fire on valid dates
rule3.hour = 0;
rule3.minute = 0;
const job3 = scheduleJob(rule3, function() {
console.log('Month-end job');
});Methods for validating and calculating recurrence rule behavior.
/**
* Check if the recurrence rule configuration is valid
* @returns {boolean} True if rule is valid
*/
RecurrenceRule.prototype.isValid = function();
/**
* Calculate the next date that matches this recurrence rule
* @param {Date} [base] - Base date to calculate from (defaults to current time)
* @returns {Date|null} Next matching date or null if no future dates match
*/
RecurrenceRule.prototype.nextInvocationDate = function(base);
/**
* Internal method for calculating next invocation date (internal use)
* @param {Date} base - Base date to calculate from
* @returns {Date|null} Next matching date or null
*/
RecurrenceRule.prototype._nextInvocationDate = function(base);Define ranges of values for use in recurrence rule specifications.
/**
* Create a range for use in recurrence rules
* @param {number} [start=0] - Range start value (inclusive)
* @param {number} [end=60] - Range end value (inclusive)
* @param {number} [step=1] - Step between values in range
*/
function Range(start?, end?, step?);
class Range {
/** Range start value */
start: number;
/** Range end value */
end: number;
/** Step between values */
step: number;
}Usage Examples:
const { Range, RecurrenceRule, scheduleJob } = require('node-schedule');
// Every 5 minutes from 0 to 55
const every5Minutes = new Range(0, 55, 5); // 0, 5, 10, 15, ..., 55
const rule = new RecurrenceRule();
rule.minute = every5Minutes;
const job = scheduleJob(rule, function() {
console.log('Runs every 5 minutes');
});
// Business hours: 9 AM to 5 PM
const businessHours = new Range(9, 17);
rule.hour = businessHours;
// Weekdays only
const weekdays = new Range(1, 5); // Monday=1 to Friday=5
rule.dayOfWeek = weekdays;Methods for working with range objects.
/**
* Check if a value falls within this range
* @param {number} val - Value to check
* @returns {boolean} True if the value is in the range
*/
Range.prototype.contains = function(val);Alternative syntax using object literals instead of RecurrenceRule instances.
/**
* Object-literal recurrence specification
* Each property can be a single value, array of values, or Range
*/
interface RecurrenceSpec {
/** Year specification */
year?: number | number[] | Range;
/** Month specification (0-11) */
month?: number | number[] | Range;
/** Day of month specification (1-31) */
date?: number | number[] | Range;
/** Day of week specification (0-6, Sunday=0) */
dayOfWeek?: number | number[] | Range;
/** Hour specification (0-23) */
hour?: number | number[] | Range;
/** Minute specification (0-59) */
minute?: number | number[] | Range;
/** Second specification (0-59) */
second?: number | number[] | Range;
}Usage Examples:
const schedule = require('node-schedule');
// Object literal syntax - every Tuesday and Thursday at 2:30 PM
const job1 = schedule.scheduleJob({
dayOfWeek: [2, 4], // Tuesday and Thursday
hour: 14,
minute: 30
}, function() {
console.log('Bi-weekly meeting reminder');
});
// Multiple values and ranges
const job2 = schedule.scheduleJob({
month: [0, 3, 6, 9], // Quarterly: Jan, Apr, Jul, Oct
date: 1, // First day of month
hour: 8,
minute: 0
}, function() {
console.log('Quarterly report');
});
// Complex scheduling with ranges
const { Range } = require('node-schedule');
const job3 = schedule.scheduleJob({
dayOfWeek: new Range(1, 5), // Weekdays
hour: [9, 12, 15], // 9 AM, noon, 3 PM
minute: [0, 30] // On the hour and half-hour
}, function() {
console.log('Regular check-in');
});Schedule jobs with recurrence rules and temporal boundaries.
/**
* Schedule specification with temporal boundaries
*/
interface ScheduleSpec {
/** Recurrence rule or cron string */
rule: RecurrenceRule | string;
/** Start date for scheduling (job won't run before this) */
start?: Date;
/** End date for scheduling (job won't run after this) */
end?: Date;
/** Timezone for date calculations */
tz?: string;
}Usage Examples:
const schedule = require('node-schedule');
// Campaign that runs for a specific period
const campaignRule = new schedule.RecurrenceRule();
campaignRule.hour = [9, 12, 15, 18]; // 4 times daily
campaignRule.minute = 0;
const campaignJob = schedule.scheduleJob({
rule: campaignRule,
start: new Date('2024-01-01'),
end: new Date('2024-01-31'),
tz: 'America/New_York'
}, function() {
console.log('Campaign reminder');
});
// Event reminders leading up to a deadline
const reminderRule = new schedule.RecurrenceRule();
reminderRule.hour = 9;
reminderRule.minute = 0;
const reminderJob = schedule.scheduleJob({
rule: reminderRule,
start: new Date('2024-02-01'),
end: new Date('2024-02-14') // Valentine's Day
}, function() {
console.log('Valentine\'s Day reminder');
});Low-level functions exposed primarily for testing and advanced use cases. These functions are part of the internal scheduling mechanism.
/**
* Schedule an invocation for execution (internal use)
* @param {Invocation} invocation - Invocation to schedule
*/
function scheduleInvocation(invocation);
/**
* Cancel a pending invocation (internal use)
* @param {Invocation} invocation - Invocation to cancel
*/
function cancelInvocation(invocation);
/**
* Schedule the next recurrence of a recurring job (internal use)
* @param {RecurrenceRule} rule - Recurrence rule
* @param {Job} job - Job instance
* @param {Date} [prevDate] - Previous execution date
* @param {Date} [endDate] - Optional end date
* @returns {Invocation|null} Next invocation or null
*/
function scheduleNextRecurrence(rule, job, prevDate?, endDate?);
/**
* Comparator function for sorting invocations by fire date (internal use)
* @param {Invocation} a - First invocation
* @param {Invocation} b - Second invocation
* @returns {number} Comparison result for sorting
*/
function sorter(a, b);
/**
* Internal array of all scheduled invocations
* Used for internal scheduling management and testing
*/
const _invocations: Invocation[];Node Schedule supports standard cron expressions with an optional seconds field.
Cron Format:
* * * * * *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ │
│ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
│ │ │ │ └───── month (1 - 12)
│ │ │ └────────── day of month (1 - 31)
│ │ └─────────────── hour (0 - 23)
│ └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, OPTIONAL)Usage Examples:
const schedule = require('node-schedule');
// Every 30 seconds
const job1 = schedule.scheduleJob('*/30 * * * * *', function() {
console.log('Every 30 seconds');
});
// At 2:30 PM every day
const job2 = schedule.scheduleJob('0 30 14 * * *', function() {
console.log('Daily at 2:30 PM');
});
// Every 5 minutes during business hours (9 AM - 5 PM) on weekdays
const job3 = schedule.scheduleJob('0 */5 9-17 * * 1-5', function() {
console.log('Business hours reminder');
});
// First day of every month at midnight
const job4 = schedule.scheduleJob('0 0 0 1 * *', function() {
console.log('Monthly job');
});Handle scheduling across different timezones using timezone identifiers.
Usage Examples:
const schedule = require('node-schedule');
// Schedule in specific timezone
const rule = new schedule.RecurrenceRule();
rule.hour = 9;
rule.minute = 0;
rule.tz = 'America/New_York';
const easternJob = schedule.scheduleJob(rule, function() {
console.log('9 AM Eastern Time job');
});
// Multiple timezone jobs
const timezones = ['America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles'];
timezones.forEach(tz => {
const tzRule = new schedule.RecurrenceRule();
tzRule.hour = 8;
tzRule.minute = 0;
tzRule.tz = tz;
schedule.scheduleJob(`morning-${tz.split('/')[1]}`, tzRule, function() {
console.log(`Good morning from ${tz}!`);
});
});Examples of valid and invalid rule configurations.
Usage Examples:
const { RecurrenceRule, Range } = require('node-schedule');
// Valid rules
const validRule1 = new RecurrenceRule();
validRule1.month = new Range(0, 11); // All months
validRule1.hour = 12;
console.log('Valid:', validRule1.isValid()); // true
const validRule2 = new RecurrenceRule();
validRule2.dayOfWeek = [0, 6]; // Weekends
validRule2.hour = [10, 14, 18];
console.log('Valid:', validRule2.isValid()); // true
// Invalid rules (will return false for isValid())
const invalidRule1 = new RecurrenceRule();
invalidRule1.hour = 25; // Hours only go 0-23
console.log('Invalid hour:', invalidRule1.isValid()); // false
const invalidRule2 = new RecurrenceRule();
invalidRule2.minute = -5; // Minutes must be 0-59
console.log('Invalid minute:', invalidRule2.isValid()); // false
const invalidRule3 = new RecurrenceRule();
invalidRule3.month = 1; // February
invalidRule3.date = 30; // February never has 30 days
console.log('Invalid date:', invalidRule3.isValid()); // false
// Testing next invocation calculation
const testRule = new RecurrenceRule();
testRule.hour = 9;
testRule.minute = 0;
const nextRun = testRule.nextInvocationDate();
console.log('Next 9 AM:', nextRun);
// Rule that will never match (returns null)
const neverRule = new RecurrenceRule();
neverRule.year = 2020; // Past year
neverRule.month = 1;
neverRule.date = 1;
const neverDate = neverRule.nextInvocationDate();
console.log('Never runs:', neverDate); // nullCommon error scenarios and their handling:
Usage Examples:
const schedule = require('node-schedule');
try {
// This will throw RangeError: Invalid number of arguments
const invalidJob = schedule.scheduleJob(function() {
console.log('Missing schedule spec');
});
} catch (error) {
console.error('Scheduling error:', error.message);
}
try {
// This will throw RangeError: The job method must be a function
const invalidJob = schedule.scheduleJob('0 * * * *', 'not a function');
} catch (error) {
console.error('Job method error:', error.message);
}
// Invalid cron expression handling
const badCronJob = schedule.scheduleJob('invalid cron', function() {
console.log('This will not be scheduled');
});
console.log('Bad cron job:', badCronJob); // null
// Rescheduling one-off jobs by name throws Error
const oneOffJob = schedule.scheduleJob('oneOff', new Date(Date.now() + 5000), function() {
console.log('One-off job');
});
try {
schedule.rescheduleJob('oneOff', new Date(Date.now() + 10000));
} catch (error) {
console.error('Reschedule error:', error.message); // Cannot reschedule one-off job by name
}