npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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-scheduler

Features

  • 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 minutes
  • 0 */2 * * * - Every 2 hours
  • 0 9 * * 1 - Every Monday at 9:00 AM
  • 0 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 job
  • scheduleAt(date, handler, options?) - Schedule one-time job
  • cancel(jobId) - Cancel a job
  • pause(jobId) - Pause a job
  • resume(jobId) - Resume a paused job
  • getJob(jobId) - Get job by ID
  • getAllJobs() - Get all jobs
  • getJobsByStatus(status) - Filter jobs by status
  • getJobStatistics(jobId) - Get job statistics
  • getSchedulerStatistics() - Get overall statistics
  • validateCronExpression(expression) - Validate cron expression
  • cancelAll() - Cancel all jobs
  • shutdown() - Shutdown scheduler

ScheduledJob

Represents a scheduled job instance.

Methods

  • getId() - Get job ID
  • getName() - Get job name
  • getType() - Get job type (recurring/one-time)
  • getStatus() - Get current status
  • getConfig() - Get job configuration
  • getExecutions() - Get execution history
  • getStatistics() - Get job statistics
  • start() - Start job execution
  • pause() - Pause job
  • resume() - Resume job
  • cancel() - 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 integration
  • cron-parser - Cron expression parsing

See Also

License

Copyright (c) 2025 Bernier LLC. All rights reserved.