agenda vs cron vs later vs node-schedule vs scheduler
スケジューリングとジョブ管理
agendacronlaternode-schedulescheduler類似パッケージ:

スケジューリングとジョブ管理

スケジューリングとジョブ管理ライブラリは、Node.jsアプリケーション内で定期的なタスクやバックグラウンドジョブを実行するためのツールです。これらのライブラリは、特定の時間や間隔で自動的にコードを実行する機能を提供し、データの定期的な処理、通知の送信、メンテナンスタスクの実行など、さまざまな用途に利用されます。これにより、開発者は手動でタスクをトリガーする必要がなくなり、アプリケーションの効率性と自動化が向上します。agendaはMongoDBを使用したジョブスケジューラーで、柔軟なスケジューリングとジョブの再試行機能を提供します。cronはUnixのcronに触発されたシンプルなスケジューラーで、定期的なタスクを簡単に設定できます。laterは自然言語のようなスケジューリングをサポートし、複雑なスケジュールを簡単に定義できます。node-scheduleはJavaScriptのDateオブジェクトを使用したスケジューラーで、特定の日時や繰り返しのタスクを設定できます。schedulerはシンプルで軽量なスケジューリングライブラリで、タスクの遅延実行や繰り返し実行をサポートします。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
agenda09,652297 kB216日前MIT
cron08,919161 kB294ヶ月前MIT
later02,417-9811年前MIT
node-schedule09,21535 kB1713年前MIT
scheduler0244,57482.7 kB1,2367ヶ月前MIT

機能比較: agenda vs cron vs later vs node-schedule vs scheduler

スケジューリングの柔軟性

  • agenda:

    agendaは、MongoDBを使用してジョブを永続化し、柔軟なスケジューリングが可能です。ジョブの再試行やキャンセル、特定の条件に基づく実行がサポートされています。

  • cron:

    cronは、Unixのcronスタイルの構文を使用して定期的なタスクを簡単に設定できますが、柔軟性は限られています。特に、単純な繰り返しタスクに適しています。

  • later:

    laterは、自然言語に近い形で複雑なスケジュールを定義できるため、非常に柔軟です。特定の時間、日、週、月に基づいたスケジューリングが可能です。

  • node-schedule:

    node-scheduleは、JavaScriptのDateオブジェクトを使用して特定の日時や繰り返しのタスクを設定できます。Cronスタイルのスケジューリングもサポートしており、比較的柔軟です。

  • scheduler:

    schedulerは、シンプルなスケジューリングを提供しますが、柔軟性は限られています。タスクの遅延実行や繰り返し実行が可能ですが、複雑なスケジュールには向いていません。

ジョブの永続化

  • agenda:

    agendaは、ジョブをMongoDBに永続化するため、アプリケーションが再起動してもジョブの状態が保持されます。これにより、ジョブの再試行や履歴管理が可能です。

  • cron:

    cronは、ジョブの永続化機能を持っていません。アプリケーションが再起動すると、スケジュールされたタスクは失われます。

  • later:

    laterは、ジョブの永続化機能を提供していません。スケジュールはメモリ内で管理されるため、アプリケーションが再起動するとスケジュールが失われます。

  • node-schedule:

    node-scheduleは、ジョブの永続化機能を持っていません。スケジュールされたタスクはメモリ内で管理されるため、アプリケーションが再起動すると失われます。

  • scheduler:

    schedulerは、ジョブの永続化機能を提供していません。シンプルなスケジューリングを提供しますが、ジョブの状態はメモリ内で管理されます。

再試行機能

  • agenda:

    agendaは、ジョブの再試行機能をサポートしており、失敗したジョブを自動的に再試行する設定が可能です。再試行の回数や間隔をカスタマイズできます。

  • cron:

    cronは、再試行機能を提供していません。ジョブが失敗した場合の処理はアプリケーション側で実装する必要があります。

  • later:

    laterは、再試行機能を提供していません。ジョブが失敗した場合の処理はアプリケーション側で実装する必要があります。

  • node-schedule:

    node-scheduleは、再試行機能を提供していません。ジョブが失敗した場合の処理はアプリケーション側で実装する必要があります。

  • scheduler:

    schedulerは、再試行機能を提供していません。ジョブが失敗した場合の処理はアプリケーション側で実装する必要があります。

シンプルさと使いやすさ

  • agenda:

    agendaは、MongoDBとの統合が必要ですが、ジョブのスケジューリングや管理は比較的簡単です。ドキュメントも充実しており、使いやすいです。

  • cron:

    cronは、シンプルなAPIとUnixスタイルの構文で、使いやすさが特徴です。特に、定期的なタスクのスケジューリングが簡単です。

  • later:

    laterは、自然言語に近いスケジューリングが可能ですが、柔軟性が高いため、使いこなすには少し学習が必要です。

  • node-schedule:

    node-scheduleは、シンプルなAPIで特定の日時や繰り返しのタスクを設定できます。使いやすく、ドキュメントも充実しています。

  • scheduler:

    schedulerは、シンプルで軽量なスケジューリングライブラリで、使いやすさが特徴です。特に小規模なプロジェクトに適しています。

Ease of Use: Code Examples

  • agenda:

    agendaのジョブスケジューリング例

    const Agenda = require('agenda');
    const agenda = new Agenda({ db: { address: 'mongodb://localhost/agenda' } });
    
    // ジョブの定義
    agenda.define('send email', async job => {
      console.log('Email sent!');
    });
    
    // ジョブのスケジューリング
    agenda.schedule('in 1 hour', 'send email');
    
    // アジェンダの開始
    agenda.start();
    
  • cron:

    cronのジョブスケジューリング例

    const { CronJob } = require('cron');
    
    const job = new CronJob('0 * * * *', () => {
      console.log('毎時0分に実行されるジョブ');
    });
    
    job.start();
    
  • later:

    laterのジョブスケジューリング例

    const later = require('later');
    
    // スケジュールの定義
    const schedule = later.parse.text('every 1 hour');
    
    // ジョブの実行
    later.setInterval(() => {
      console.log('1時間ごとに実行されるジョブ');
    }, schedule);
    
  • node-schedule:

    node-scheduleのジョブスケジューリング例

    const schedule = require('node-schedule');
    
    const job = schedule.scheduleJob('*/5 * * * *', () => {
      console.log('5分ごとに実行されるジョブ');
    });
    
    // ジョブのキャンセル
    // job.cancel();
    
  • scheduler:

    schedulerのジョブスケジューリング例

    const { Scheduler } = require('scheduler');
    const scheduler = new Scheduler();
    
    scheduler.schedule(() => {
      console.log('遅延実行されるタスク');
    }, 1000);
    

選び方: agenda vs cron vs later vs node-schedule vs scheduler

  • agenda:

    agendaは、MongoDBを使用してジョブを永続化し、再試行やキャンセルが可能な柔軟なスケジューリングが必要な場合に最適です。特に、ジョブの状態管理や履歴が重要なアプリケーションに適しています。

  • cron:

    cronは、シンプルで軽量な定期的タスクのスケジューリングが必要な場合に適しています。複雑な設定は不要で、Unixのcronスタイルの構文に慣れている開発者にとって使いやすいです。

  • later:

    laterは、自然言語に近い形で複雑なスケジュールを定義したい場合に最適です。特に、特定の時間や日付に基づいた柔軟なスケジューリングが必要な場合に便利です。

  • node-schedule:

    node-scheduleは、JavaScriptのDateオブジェクトを使用して特定の日時や繰り返しのタスクを簡単に設定したい場合に適しています。シンプルなAPIで、軽量なスケジューリングが可能です。

  • scheduler:

    schedulerは、シンプルで軽量なスケジューリングが必要な場合に適しています。タスクの遅延実行や繰り返し実行をサポートしており、特に小規模なプロジェクトやシンプルなタスクに適しています。

agenda のREADME

Agenda

Agenda

A light-weight job scheduling library for Node.js

NPM Version NPM Downloads

Migrating from v5? See the Migration Guide for all breaking changes.

Agenda 6.x

Agenda 6.x is a complete TypeScript rewrite with a focus on modularity and flexibility:

  • Pluggable storage backends - Choose from MongoDB, PostgreSQL, Redis, or implement your own. Each backend is a separate package - install only what you need.

  • Pluggable notification channels - Move beyond polling with real-time job notifications via Redis, PostgreSQL LISTEN/NOTIFY, or other pub/sub systems. Jobs get processed immediately when saved, not on the next poll cycle.

  • Modern stack - ESM-only, Node.js 18+, full TypeScript with strict typing.

See the 6.x Roadmap for details and progress.

Features

  • Minimal overhead job scheduling
  • Pluggable storage backends (MongoDB, PostgreSQL, Redis)
  • TypeScript support with full typing
  • Scheduling via cron or human-readable syntax
  • Configurable concurrency and locking
  • Real-time job notifications (optional)
  • Sandboxed worker execution via fork mode
  • TypeScript decorators for class-based job definitions

Installation

Install the core package and your preferred backend:

# For MongoDB
npm install agenda @agendajs/mongo-backend

# For PostgreSQL
npm install agenda @agendajs/postgres-backend

# For Redis
npm install agenda @agendajs/redis-backend

Requirements:

  • Node.js 18+
  • Database of your choice (MongoDB 4+, PostgreSQL, or Redis)

Quick Start

import { Agenda } from 'agenda';
import { MongoBackend } from '@agendajs/mongo-backend';

const agenda = new Agenda({
  backend: new MongoBackend({ address: 'mongodb://localhost/agenda' })
});

// Define a job
agenda.define('send email', async (job) => {
  const { to, subject } = job.attrs.data;
  await sendEmail(to, subject);
});

// Start processing
await agenda.start();

// Schedule jobs
await agenda.every('1 hour', 'send email', { to: 'user@example.com', subject: 'Hello' });
await agenda.schedule('in 5 minutes', 'send email', { to: 'admin@example.com', subject: 'Report' });
await agenda.now('send email', { to: 'support@example.com', subject: 'Urgent' });

Official Backend Packages

PackageBackendNotificationsInstall
@agendajs/mongo-backendMongoDBPolling onlynpm install @agendajs/mongo-backend
@agendajs/postgres-backendPostgreSQLLISTEN/NOTIFYnpm install @agendajs/postgres-backend
@agendajs/redis-backendRedisPub/Subnpm install @agendajs/redis-backend

Backend Capabilities

BackendStorageNotificationsNotes
MongoDB (MongoBackend)Storage only. Combine with external notification channel for real-time.
PostgreSQL (PostgresBackend)Full backend. Uses LISTEN/NOTIFY for notifications.
Redis (RedisBackend)Full backend. Uses Pub/Sub for notifications.
InMemoryNotificationChannelNotifications only. For single-process/testing.

Backend Configuration

MongoDB

import { Agenda } from 'agenda';
import { MongoBackend } from '@agendajs/mongo-backend';

// Via connection string
const agenda = new Agenda({
  backend: new MongoBackend({ address: 'mongodb://localhost/agenda' })
});

// Via existing MongoDB connection
const agenda = new Agenda({
  backend: new MongoBackend({ mongo: existingDb })
});

// With options
const agenda = new Agenda({
  backend: new MongoBackend({
    mongo: db,
    collection: 'jobs'        // Collection name (default: 'agendaJobs')
  }),
  processEvery: '30 seconds', // Job polling interval
  maxConcurrency: 20,         // Max concurrent jobs
  defaultConcurrency: 5       // Default per job type
});

PostgreSQL

import { Agenda } from 'agenda';
import { PostgresBackend } from '@agendajs/postgres-backend';

const agenda = new Agenda({
  backend: new PostgresBackend({
    connectionString: 'postgresql://user:pass@localhost:5432/mydb'
  })
});

Redis

import { Agenda } from 'agenda';
import { RedisBackend } from '@agendajs/redis-backend';

const agenda = new Agenda({
  backend: new RedisBackend({
    connectionString: 'redis://localhost:6379'
  })
});

Real-Time Notifications

For faster job processing across distributed systems:

import { Agenda, InMemoryNotificationChannel } from 'agenda';
import { MongoBackend } from '@agendajs/mongo-backend';

const agenda = new Agenda({
  backend: new MongoBackend({ mongo: db }),
  notificationChannel: new InMemoryNotificationChannel()
});

Mixing Storage and Notification Backends

You can use MongoDB for storage while using a different system for real-time notifications:

import { Agenda } from 'agenda';
import { MongoBackend } from '@agendajs/mongo-backend';
import { RedisBackend } from '@agendajs/redis-backend';

// MongoDB for storage + Redis for real-time notifications
const redisBackend = new RedisBackend({ connectionString: 'redis://localhost:6379' });
const agenda = new Agenda({
  backend: new MongoBackend({ mongo: db }),
  notificationChannel: redisBackend.notificationChannel
});

This is useful when you want MongoDB's proven durability and flexible queries for job storage, but need faster real-time notifications across multiple processes.

API Overview

Defining Jobs

// Simple async handler
agenda.define('my-job', async (job) => {
  console.log('Processing:', job.attrs.data);
});

// With options
agenda.define('my-job', async (job) => { /* ... */ }, {
  concurrency: 10,
  lockLimit: 5,
  lockLifetime: 10 * 60 * 1000, // 10 minutes
  priority: 'high'
});

Defining Jobs with Decorators

For a class-based approach, use TypeScript decorators:

import { JobsController, Define, Every, registerJobs, Job } from 'agenda';

@JobsController({ namespace: 'email' })
class EmailJobs {
  @Define({ concurrency: 5 })
  async sendWelcome(job: Job<{ userId: string }>) {
    console.log('Sending welcome to:', job.attrs.data.userId);
  }

  @Every('1 hour')
  async cleanupBounced(job: Job) {
    console.log('Cleaning up bounced emails');
  }
}

registerJobs(agenda, [new EmailJobs()]);
await agenda.start();

// Schedule using namespaced name
await agenda.now('email.sendWelcome', { userId: '123' });

See Decorators Documentation for full details.

Scheduling Jobs

// Run immediately
await agenda.now('my-job', { userId: '123' });

// Run at specific time
await agenda.schedule('tomorrow at noon', 'my-job', data);
await agenda.schedule(new Date('2024-12-25'), 'my-job', data);

// Run repeatedly
await agenda.every('5 minutes', 'my-job');
await agenda.every('0 * * * *', 'my-job'); // Cron syntax

Job Control

// Cancel jobs matching a filter (removes from database)
await agenda.cancel({ name: 'my-job' });
await agenda.cancel({ name: 'my-job', data: { userId: 123 } });

// Cancel ALL jobs unconditionally
await agenda.cancelAll();

// Disable/enable jobs globally (by query)
await agenda.disable({ name: 'my-job' });  // Disable all jobs matching query
await agenda.enable({ name: 'my-job' });   // Enable all jobs matching query

// Disable/enable individual jobs
const job = await agenda.create('my-job', data);
job.disable();
await job.save();

// Progress tracking
agenda.define('long-job', async (job) => {
  for (let i = 0; i <= 100; i += 10) {
    await doWork();
    await job.touch(i); // Report progress 0-100
  }
});

Stopping / Draining

// Stop immediately - unlocks running jobs so other workers can pick them up
await agenda.stop();

// Drain - waits for running jobs to complete before stopping
await agenda.drain();

// Drain with timeout (30 seconds) - for cloud platforms with shutdown deadlines
const result = await agenda.drain(30000);
if (result.timedOut) {
    console.log(`${result.running} jobs still running after timeout`);
}

// Drain with AbortSignal - for external control
const controller = new AbortController();
setTimeout(() => controller.abort(), 30000);
await agenda.drain({ signal: controller.signal });

Use drain() for graceful shutdowns where you want in-progress jobs to finish their work.

Events

agenda.on('start', (job) => console.log('Job started:', job.attrs.name));
agenda.on('complete', (job) => console.log('Job completed:', job.attrs.name));
agenda.on('success', (job) => console.log('Job succeeded:', job.attrs.name));
agenda.on('fail', (err, job) => console.log('Job failed:', job.attrs.name, err));

// Job-specific events
agenda.on('start:send email', (job) => { /* ... */ });
agenda.on('fail:send email', (err, job) => { /* ... */ });

Custom Backend

For databases other than MongoDB, PostgreSQL, or Redis, implement AgendaBackend:

import { AgendaBackend, JobRepository } from 'agenda';

class SQLiteBackend implements AgendaBackend {
  readonly repository: JobRepository;
  readonly notificationChannel = undefined; // Or implement NotificationChannel

  async connect() { /* ... */ }
  async disconnect() { /* ... */ }
}

const agenda = new Agenda({
  backend: new SQLiteBackend({ path: './jobs.db' })
});

See Custom Backend Driver for details.

Documentation

Related Packages

Official Backend Packages:

Tools:

License

MIT