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