Skip to main content

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 immediately
  • scheduler.schedule() - Execute once at a specific time
  • scheduler.every() - Execute repeatedly
  • scheduler.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