Creating Jobs
Learn all the ways to schedule and create jobs in Chronos, from immediate execution to complex recurring patterns.
Job Creation Methods
Chronos provides several methods to create and schedule jobs:
scheduler.now()
- Execute immediatelyscheduler.schedule()
- Execute once at a specific timescheduler.every()
- Execute repeatedlyscheduler.create()
- Create without scheduling
Immediate Execution
scheduler.now(jobName, [data])
Execute a job immediately:
// Simple immediate execution
await scheduler.now('send-notification');
// With data
await scheduler.now('send-email', {
to: 'user@example.com',
subject: 'Welcome!',
body: 'Thanks for signing up'
});
// Multiple jobs at once
await scheduler.now(['job1', 'job2', 'job3']);
Returns a Job
instance or array of Job
instances.
Scheduled Execution
scheduler.schedule(when, jobName, [data])
Schedule a job to run once at a specific time:
// Using relative time expressions
await scheduler.schedule('in 30 minutes', 'send-reminder');
await scheduler.schedule('in 2 hours', 'process-data');
await scheduler.schedule('tomorrow at 9am', 'daily-report');
// Using Date objects
const futureDate = new Date('2024-12-25 09:00:00');
await scheduler.schedule(futureDate, 'christmas-greeting');
// Using ISO strings
await scheduler.schedule('2024-01-15T14:30:00Z', 'meeting-reminder');
// With job data
await scheduler.schedule('in 1 hour', 'send-email', {
to: 'admin@example.com',
subject: 'Scheduled Report',
reportType: 'weekly'
});
Time Expression Examples
Chronos accepts various time formats:
// Relative times
await scheduler.schedule('in 5 minutes', 'job-name');
await scheduler.schedule('in 2 hours', 'job-name');
await scheduler.schedule('in 3 days', 'job-name');
await scheduler.schedule('in 1 week', 'job-name');
// Natural language
await scheduler.schedule('tomorrow', 'job-name');
await scheduler.schedule('next monday', 'job-name');
await scheduler.schedule('tomorrow at 2pm', 'job-name');
await scheduler.schedule('next friday at 5:30pm', 'job-name');
// Specific dates
await scheduler.schedule('December 25th at 9am', 'job-name');
await scheduler.schedule('2024-01-01 00:00:00', 'job-name');
Recurring Jobs
scheduler.every(interval, jobName, [data], [options])
Create jobs that repeat on an interval:
// Simple intervals
await scheduler.every('5 minutes', 'health-check');
await scheduler.every('1 hour', 'cleanup-temp-files');
await scheduler.every('1 day', 'daily-backup');
// With data
await scheduler.every('30 minutes', 'send-notifications', {
type: 'reminder',
priority: 'low'
});
// Multiple jobs with same interval
await scheduler.every('1 hour', ['cleanup', 'health-check', 'metrics']);
Cron Expression Support
Use cron expressions for precise scheduling:
// Every weekday at 9 AM
await scheduler.every('0 9 * * 1-5', 'morning-report');
// Every first day of the month at midnight
await scheduler.every('0 0 1 * *', 'monthly-billing');
// Every 15 minutes during business hours
await scheduler.every('*/15 9-17 * * 1-5', 'business-hours-check');
// Custom cron examples
await scheduler.every('30 2 * * *', 'daily-backup'); // 2:30 AM daily
await scheduler.every('0 */6 * * *', 'six-hour-sync'); // Every 6 hours
await scheduler.every('0 9 * * MON', 'weekly-report'); // Monday 9 AM
Advanced Recurring Options
Control recurring job behavior with options:
await scheduler.every('1 hour', 'data-sync', {}, {
timezone: 'America/New_York', // Timezone for scheduling
skipImmediate: true, // Don't run immediately
startDate: new Date('2024-01-01'), // First run date
endDate: new Date('2024-12-31'), // Last run date
skipDays: '2 days' // Skip period after each run
});
Timezone Support
// Run at 9 AM New York time
await scheduler.every('0 9 * * *', 'morning-job', {}, {
timezone: 'America/New_York'
});
// Run at 6 PM London time
await scheduler.every('0 18 * * *', 'evening-job', {}, {
timezone: 'Europe/London'
});
Skip Immediate Execution
// Create recurring job but don't run immediately
await scheduler.every('1 day', 'daily-task', {}, {
skipImmediate: true
});
Date Range Limits
// Only run during 2024
await scheduler.every('1 day', 'year-2024-task', {}, {
startDate: new Date('2024-01-01'),
endDate: new Date('2024-12-31')
});
Manual Job Creation
scheduler.create(jobName, data)
Create a job without scheduling it:
const job = scheduler.create('process-order', {
orderId: '12345',
customerId: 'cust-789'
});
// Configure the job
job.priority('high');
job.schedule('in 30 minutes');
job.unique({ 'data.orderId': '12345' });
// Save to database
await job.save();
This is useful when you need to configure jobs before scheduling them.
Job Configuration
Configure jobs after creation but before saving:
Priority
const job = scheduler.create('important-task', { id: 1 });
job.priority('high');
await job.save();
Scheduling
const job = scheduler.create('future-task', {});
// Schedule for specific time
job.schedule('tomorrow at 2pm');
// Or use repeatEvery for recurring
job.repeatEvery('1 day');
await job.save();
Uniqueness
Ensure only one instance of a job exists:
const job = scheduler.create('user-notification', {
userId: '123',
type: 'welcome'
});
// Make unique by userId and type
job.unique({
'data.userId': '123',
'data.type': 'welcome'
});
await job.save();
// Subsequent saves with same data won't create duplicates
Result Persistence
const job = scheduler.create('data-processor', { file: 'data.csv' });
job.setShouldSaveResult(true);
await job.save();
Batch Job Creation
Create multiple jobs efficiently:
// Create multiple related jobs
const users = await User.find({ needsEmail: true });
const jobs = users.map(user => {
return scheduler.create('send-email', {
userId: user._id,
template: 'newsletter',
to: user.email
});
});
// Save all jobs
await Promise.all(jobs.map(job => job.save()));
Conditional Job Creation
Create jobs based on conditions:
// Only create if job doesn't already exist
const existingJobs = await scheduler.jobs({
name: 'daily-report',
nextRunAt: { $gte: new Date() }
});
if (existingJobs.length === 0) {
await scheduler.every('1 day', 'daily-report');
}
Job Chaining
Create dependent jobs:
scheduler.define('process-file', async (job) => {
const { fileId } = job.attrs.data;
// Process file
await processFile(fileId);
// Schedule follow-up job
await scheduler.now('cleanup-temp-files', { fileId });
// Schedule notification
await scheduler.schedule('in 5 minutes', 'notify-completion', {
fileId,
processedAt: new Date()
});
});
Dynamic Scheduling
Schedule jobs based on runtime data:
scheduler.define('schedule-reminders', async (job) => {
const appointments = await Appointment.find({
date: { $gte: new Date(), $lt: tomorrow }
});
for (const appointment of appointments) {
// Schedule reminder 1 hour before
const reminderTime = new Date(appointment.date.getTime() - 60 * 60 * 1000);
await scheduler.schedule(reminderTime, 'send-reminder', {
appointmentId: appointment._id,
patientEmail: appointment.patientEmail
});
}
});
Advanced Patterns
Delayed Job Queues
// Priority queue pattern
await scheduler.now('urgent-task', { priority: 1 });
await scheduler.schedule('in 5 minutes', 'normal-task', { priority: 5 });
await scheduler.schedule('in 1 hour', 'low-priority-task', { priority: 10 });
Batch Processing
scheduler.define('batch-processor', async (job) => {
const { batchId } = job.attrs.data;
// Process items in batch
const items = await BatchItem.find({ batchId, processed: false });
for (const item of items) {
await processItem(item);
// Schedule individual follow-up if needed
if (item.needsFollowUp) {
await scheduler.schedule('in 1 day', 'follow-up-item', {
itemId: item._id
});
}
}
});
Workflow Orchestration
scheduler.define('start-workflow', async (job) => {
const { workflowId } = job.attrs.data;
// Step 1: Immediate
await scheduler.now('workflow-step-1', { workflowId });
// Step 2: After step 1 completes (handled by event)
// Step 3: Scheduled for later
await scheduler.schedule('in 1 hour', 'workflow-step-3', { workflowId });
});
// Handle step completion
scheduler.on('success:workflow-step-1', async (job) => {
const { workflowId } = job.attrs.data;
await scheduler.now('workflow-step-2', { workflowId });
});
Error Handling in Job Creation
Handle job creation failures:
try {
await scheduler.schedule('invalid-time-format', 'test-job');
} catch (error) {
console.error('Failed to schedule job:', error.message);
}
// Validate data before creating jobs
function createEmailJob(emailData) {
if (!emailData.to || !emailData.subject) {
throw new Error('Missing required email fields');
}
return scheduler.create('send-email', emailData);
}
Performance Tips
Bulk Operations
// Instead of multiple individual calls
// Avoid:
for (const user of users) {
await scheduler.now('process-user', { userId: user._id });
}
// Better: Batch the data
await scheduler.now('process-users-batch', {
userIds: users.map(u => u._id)
});
Job Deduplication
// Use unique constraints to prevent duplicates
const job = scheduler.create('daily-report', { date: '2024-01-01' });
job.unique({
name: 'daily-report',
'data.date': '2024-01-01'
});
await job.save(); // Won't create duplicate