@bernierllc/job-scheduler
v1.2.0
Published
Cron-based job scheduling for recurring tasks with execution tracking
Readme
@bernierllc/job-scheduler
Cron-based job scheduling for recurring tasks with execution tracking and history.
Installation
npm install @bernierllc/job-schedulerFeatures
- Cron Expression Support - Schedule recurring jobs using standard cron syntax
- One-Time Scheduling - Schedule jobs to run at specific dates/times
- Job Management - Pause, resume, and cancel jobs
- Execution Tracking - Complete history of job executions with success/failure status
- Retry Logic - Automatic retry with configurable delay for failed jobs
- Statistics - Job execution statistics including duration, success rate, and next run time
- TypeScript Support - Full type definitions included
- Task Queue Integration - Optional integration with @bernierllc/task-queue
- Structured Error Handling - Consistent error responses using PackageResult pattern
Usage
Basic Recurring Job
import { createJobScheduler } from '@bernierllc/job-scheduler';
const scheduler = createJobScheduler();
// Schedule a job to run every day at 9 AM
const result = scheduler.schedule('0 9 * * *', async () => {
console.log('Daily report generation');
// Your job logic here
}, {
name: 'daily-report',
metadata: { source: 'reports' }
});
if (result.success) {
console.log('Job scheduled:', result.data?.getId());
}One-Time Job
import { createJobScheduler } from '@bernierllc/job-scheduler';
const scheduler = createJobScheduler();
// Schedule a job to run at specific time
const publishDate = new Date('2025-10-15T10:00:00Z');
const result = scheduler.scheduleAt(publishDate, async () => {
console.log('Publishing blog post');
// Your job logic here
}, {
name: 'publish-post',
metadata: { postId: '12345' }
});
if (result.success) {
console.log('Job scheduled for:', publishDate.toISOString());
}Job with Retry Logic
const result = scheduler.schedule('0 * * * *', async () => {
// Job that might fail
await processData();
}, {
name: 'data-processor',
maxRetries: 3,
retryDelay: 5000 // 5 seconds
});Managing Jobs
// Pause a job
scheduler.pause(jobId);
// Resume a paused job
scheduler.resume(jobId);
// Cancel a job
scheduler.cancel(jobId);
// Cancel all jobs
scheduler.cancelAll();Retrieving Jobs
// Get specific job
const job = scheduler.getJob(jobId);
console.log('Job status:', job?.getStatus());
// Get all jobs
const allJobs = scheduler.getAllJobs();
console.log('Total jobs:', allJobs.length);
// Get jobs by status
import { JobStatus } from '@bernierllc/job-scheduler';
const activeJobs = scheduler.getJobsByStatus(JobStatus.SCHEDULED);
const pausedJobs = scheduler.getJobsByStatus(JobStatus.PAUSED);Job Statistics
// Get statistics for specific job
const stats = scheduler.getJobStatistics(jobId);
if (stats) {
console.log('Total executions:', stats.totalExecutions);
console.log('Successful:', stats.successfulExecutions);
console.log('Failed:', stats.failedExecutions);
console.log('Average duration:', stats.averageDuration, 'ms');
console.log('Last execution:', stats.lastExecution);
console.log('Next execution:', stats.nextExecution);
}
// Get overall scheduler statistics
const schedulerStats = scheduler.getSchedulerStatistics();
console.log('Total jobs:', schedulerStats.totalJobs);
console.log('Active jobs:', schedulerStats.activeJobs);
console.log('Paused jobs:', schedulerStats.pausedJobs);Execution History
const job = scheduler.getJob(jobId);
const executions = job?.getExecutions();
executions?.forEach(execution => {
console.log('Execution ID:', execution.executionId);
console.log('Start time:', execution.startTime);
console.log('Status:', execution.status);
console.log('Duration:', execution.duration, 'ms');
if (execution.error) {
console.log('Error:', execution.error);
}
});Validate Cron Expression
const validation = scheduler.validateCronExpression('0 9 * * *');
if (validation.success) {
console.log('Valid cron expression');
} else {
console.error('Invalid:', validation.error);
}Configuration
import { createJobScheduler } from '@bernierllc/job-scheduler';
const scheduler = createJobScheduler({
timezone: 'America/New_York',
maxConcurrentJobs: 10,
enableHistory: true,
historyRetention: 100,
enableTaskQueue: true,
taskQueueConfig: {
maxSize: 100,
priority: 1
}
});Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| timezone | string | 'UTC' | Timezone for cron scheduling |
| maxConcurrentJobs | number | 10 | Maximum concurrent jobs |
| enableHistory | boolean | true | Enable execution history tracking |
| historyRetention | number | 100 | Number of executions to retain |
| enableTaskQueue | boolean | false | Enable task queue integration |
| taskQueueConfig | object | - | Task queue configuration |
Cron Expression Format
The scheduler supports standard cron expressions:
┌───────────── second (optional, 0-59)
│ ┌───────────── minute (0-59)
│ │ ┌───────────── hour (0-23)
│ │ │ ┌───────────── day of month (1-31)
│ │ │ │ ┌───────────── month (1-12)
│ │ │ │ │ ┌───────────── day of week (0-7, 0 and 7 are Sunday)
│ │ │ │ │ │
│ │ │ │ │ │
* * * * * *Examples
0 9 * * *- Every day at 9:00 AM*/15 * * * *- Every 15 minutes0 */2 * * *- Every 2 hours0 9 * * 1- Every Monday at 9:00 AM0 0 1 * *- First day of every month at midnight* * * * * *- Every second (with second precision)
API Reference
JobScheduler
Main scheduler class for managing jobs.
Methods
schedule(cronExpression, handler, options?)- Schedule recurring jobscheduleAt(date, handler, options?)- Schedule one-time jobcancel(jobId)- Cancel a jobpause(jobId)- Pause a jobresume(jobId)- Resume a paused jobgetJob(jobId)- Get job by IDgetAllJobs()- Get all jobsgetJobsByStatus(status)- Filter jobs by statusgetJobStatistics(jobId)- Get job statisticsgetSchedulerStatistics()- Get overall statisticsvalidateCronExpression(expression)- Validate cron expressioncancelAll()- Cancel all jobsshutdown()- Shutdown scheduler
ScheduledJob
Represents a scheduled job instance.
Methods
getId()- Get job IDgetName()- Get job namegetType()- Get job type (recurring/one-time)getStatus()- Get current statusgetConfig()- Get job configurationgetExecutions()- Get execution historygetStatistics()- Get job statisticsstart()- Start job executionpause()- Pause jobresume()- Resume jobcancel()- Cancel job
Types
enum JobStatus {
SCHEDULED = 'scheduled',
RUNNING = 'running',
PAUSED = 'paused',
COMPLETED = 'completed',
FAILED = 'failed',
CANCELLED = 'cancelled'
}
enum JobType {
RECURRING = 'recurring',
ONE_TIME = 'one-time'
}
interface JobExecution {
executionId: string;
jobId: string;
startTime: Date;
endTime?: Date;
status: JobStatus;
error?: string;
duration?: number;
}
interface JobStatistics {
totalExecutions: number;
successfulExecutions: number;
failedExecutions: number;
averageDuration: number;
lastExecution?: Date;
nextExecution?: Date;
}
interface JobSchedulerResult<T = unknown> {
success: boolean;
data?: T;
error?: string;
}Advanced Usage
Custom Job Names and Metadata
const result = scheduler.schedule('0 * * * *', handler, {
name: 'hourly-sync',
metadata: {
source: 'external-api',
priority: 'high',
owner: 'data-team'
}
});
// Access metadata later
const job = scheduler.getJob(result.data!.getId());
const config = job.getConfig();
console.log('Metadata:', config.metadata);Monitoring Job Execution
const job = scheduler.getJob(jobId);
// Check current status
console.log('Status:', job.getStatus());
// Get detailed statistics
const stats = job.getStatistics();
console.log('Success rate:',
(stats.successfulExecutions / stats.totalExecutions * 100).toFixed(2) + '%'
);
// Get execution history
const executions = job.getExecutions();
const recentFailures = executions
.filter(e => e.status === JobStatus.FAILED)
.slice(-5);
recentFailures.forEach(failure => {
console.log('Failed at:', failure.startTime);
console.log('Error:', failure.error);
});Graceful Shutdown
// Cleanup on application shutdown
process.on('SIGTERM', () => {
console.log('Shutting down scheduler...');
scheduler.shutdown();
process.exit(0);
});Integration Status
Logger Integration
Status: Integrated
Justification: This package uses @bernierllc/logger for structured logging of job scheduling operations. Logs include job creation, execution start/completion, failures, retries, and scheduling events to help with debugging and monitoring job workflows.
Pattern: Direct integration - logger is a required dependency for this package.
NeverHub Integration
Status: Optional (recommended for job orchestration)
Justification: While this package can function without NeverHub, it's highly recommended to integrate @bernierllc/neverhub-adapter for job orchestration and event publishing. Job schedulers often need to coordinate with other services, and NeverHub provides a service mesh for publishing job execution events that other services can subscribe to. However, the package is designed to work without NeverHub for simpler use cases.
Pattern: Optional integration - package works without NeverHub, but NeverHub enhances job orchestration capabilities.
Example Integration:
import { NeverHubAdapter } from '@bernierllc/neverhub-adapter';
import { JobScheduler } from '@bernierllc/job-scheduler';
const neverhub = new NeverHubAdapter({ service: 'job-scheduler' });
const scheduler = new JobScheduler({ /* config */ });
// Publish job events to NeverHub
scheduler.on('job:completed', async (job) => {
await neverhub.publish('job.completed', {
jobId: job.id,
jobType: job.type,
duration: job.duration,
timestamp: new Date()
});
});Docs-Suite Integration
Status: Ready
Format: TypeDoc-compatible JSDoc comments are included throughout the source code. All public APIs are documented with examples and type information.
Error Handling
All operations return a JobSchedulerResult with structured error information:
const result = scheduler.schedule('invalid-cron', handler);
if (!result.success) {
console.error('Scheduling failed:', result.error);
// Handle error appropriately
}Dependencies
@bernierllc/logger- Logging functionality@bernierllc/task-queue- Optional task queue integrationcron-parser- Cron expression parsing
See Also
- @bernierllc/cron-scheduler - Pure cron utilities
- @bernierllc/task-queue - Task queue management
- @bernierllc/scheduler-service - High-level scheduling service
License
Copyright (c) 2025 Bernier LLC. All rights reserved.
