JSPM

  • Created
  • Published
  • Downloads 52
  • Score
    100M100P100Q95317F
  • License MIT

A high-performance, type-safe job scheduler for Node.js, inspired by Go's jcron.

Package Exports

  • @devloops/jcron
  • @devloops/jcron/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@devloops/jcron) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@devloops/jcron

JCRON Logo

A high-performance, type-safe job scheduler for Node.js, React Native, and browsers

npm version npm downloads License: MIT TypeScript Build Status React Native

FeaturesInstallationQuick StartDocumentationExamplesAPI Reference


🌟 Why JCRON?

JCRON is a next-generation cron scheduler that combines the power of Go's performance with the flexibility of TypeScript. Unlike other schedulers that rely on polling or setInterval, JCRON uses a mathematical scheduling algorithm for precise, CPU-efficient execution.

Key Highlights

  • Blazing Fast: Mathematical scheduling, not polling-based (~0.002ms per calculation)
  • 🎯 100% Cron Compatible: All standard Unix/Linux patterns work perfectly
  • 🌍 Universal: Node.js, React Native, Browsers (UMD/ESM/CJS)
  • 🔒 Type-Safe: Full TypeScript support with strict typing
  • 🌐 i18n Ready: Human-readable descriptions in 10+ languages
  • 🚀 Zero Idle CPU: Near-zero CPU usage when no jobs are running
  • 📦 Tiny Bundle: < 50KB gzipped, tree-shakeable
  • 🧪 Battle-Tested: 175+ test cases, 91.6% coverage

🎯 Features

Core Scheduling

  • Classic Cron Syntax: Full support for Unix/Linux cron patterns
  • Shortcuts: @yearly, @monthly, @weekly, @daily, @hourly, @minutely
  • Advanced Patterns:
    • L (last day/weekday of month)
    • # (nth weekday occurrence, e.g., 1#2 = 2nd Monday)
    • W (week-based, e.g., 1W3 = Monday of week 3)
    • Multiple patterns (e.g., 1#1,5#3 = 1st Monday and 3rd Friday)
  • Week of Year: WOY:33 for ISO week-based scheduling
  • End of Duration (EOD): Schedule tasks relative to period ends

Timezone & Internationalization

  • 🌍 Timezone Support: Full IANA timezone database support
  • 🔄 DST Handling: Automatic daylight saving time adjustments
  • 🗣️ Human-Readable: Convert cron expressions to natural language
  • 🌐 10+ Languages: English, Turkish, Spanish, French, German, Polish, Portuguese, Italian, Czech, Dutch

Performance & Reliability

  • Optimized Engine: Timezone caching (41x → 1.68x overhead)
  • 📊 Smart Caching: nthWeekDay caching, validation optimization
  • 🛡️ Error Recovery: Built-in retry policies and error handling
  • 🔍 Logging: Compatible with popular Node.js loggers (Winston, Pino, Bunyan)

Developer Experience

  • 📘 TypeScript-First: Full type definitions with IntelliSense
  • 🧪 Well-Tested: Comprehensive test suite with edge cases
  • 📖 Rich Documentation: API reference, examples, migration guides
  • 🔧 Flexible API: Function-based, object-based, or class-based usage

📦 Installation

# npm
npm install @devloops/jcron

# yarn
yarn add @devloops/jcron

# pnpm
pnpm add @devloops/jcron

# bun
bun add @devloops/jcron

Platform Support

Platform Support Entry Point
Node.js (CJS) ✅ Full dist/index.cjs
Node.js (ESM) ✅ Full dist/index.mjs
React Native ✅ Full dist/index.mjs
Browser (UMD) ✅ Full dist/jcron.umd.js
Browser (ESM) ✅ Full dist/index.mjs
Bun ✅ Full dist/index.mjs
Deno ✅ Full dist/index.mjs

🚀 Quick Start

Basic Usage

import { Runner } from "@devloops/jcron";

const runner = new Runner();

// Run every day at 9 AM
runner.addFuncCron("0 9 * * *", () => {
  console.log("Daily morning task executed!");
});

runner.start();

Calculate Next Run Time

import { getNext, toString } from "@devloops/jcron";

const nextRun = getNext("0 9 * * *");
console.log("Next execution:", nextRun);

const humanReadable = toString("0 9 * * *");
console.log("Description:", humanReadable); // "Daily at 9:00 AM"

Timezone-Aware Scheduling

import { Schedule, getNext } from "@devloops/jcron";

const schedule = new Schedule({
  h: "9",
  m: "0",
  tz: "America/New_York",
});

const nextRun = getNext(schedule);
console.log("Next run in NYC timezone:", nextRun);

📚 Documentation

Core Concepts

Advanced Topics


💡 Examples

1. Classic Cron Patterns

import { Runner } from "@devloops/jcron";

const runner = new Runner();

// Every 15 minutes
runner.addFuncCron("*/15 * * * *", () => {
  console.log("Runs every 15 minutes");
});

// Every weekday at 9 AM
runner.addFuncCron("0 9 * * 1-5", () => {
  console.log("Weekday morning task");
});

// First Monday of every month at midnight
runner.addFuncCron("0 0 * * 1#1", () => {
  console.log("First Monday task");
});

runner.start();

2. Advanced Patterns

import { Runner } from "@devloops/jcron";

const runner = new Runner();

// Multiple nth weekdays: 1st Monday and 3rd Friday
runner.addFuncCron("0 0 * * 1#1,5#3", () => {
  console.log("Bi-monthly specific weekdays");
});

// Week-based pattern: Monday of week 4
runner.addFuncCron("0 0 * * 1W4", () => {
  console.log("Monday of the 4th week");
});

// Last day of the month
runner.addFuncCron("0 0 L * *", () => {
  console.log("Last day of month");
});

// Last Friday of the month
runner.addFuncCron("0 0 * * 5L", () => {
  console.log("Last Friday");
});

runner.start();

3. End of Duration (EOD)

import { Schedule, Runner } from "@devloops/jcron";

const runner = new Runner();

// Run at 9 AM daily, until the end of the day
const schedule = new Schedule({
  h: "9",
  m: "0",
  eod: "E1D", // End of 1 Day
});

runner.addScheduleCron(schedule, () => {
  console.log("Daily task with EOD");
});

runner.start();

4. Human-Readable Descriptions

import { toHumanize } from "@devloops/jcron";

// Natural language descriptions
console.log(toHumanize("0 9 * * *")); // "Daily at 9:00 AM"
console.log(toHumanize("0 0 * * 0")); // "Weekly on Sunday"
console.log(toHumanize("0 0 1 * *")); // "Monthly on 1st"
console.log(toHumanize("0 0 1 1 *")); // "Yearly on January 1st"
console.log(toHumanize("0 0 * * 1-5")); // "at midnight, on weekdays"
console.log(toHumanize("0 0 * * 6,0")); // "at midnight, on weekends"
console.log(toHumanize("0 0 * * 1#2")); // "at midnight, on 2nd Monday of the month"
console.log(toHumanize("0 0 * * 1W4")); // "at midnight, on Monday of week 4"
console.log(toHumanize("*/15 9-17 * * 1-5")); // Smart time range formatting

// Multi-language support
console.log(toHumanize("0 9 * * *", { locale: "tr" })); // "Günlük saat 9:00"
console.log(toHumanize("0 9 * * *", { locale: "de" })); // "Täglich um 9:00"
console.log(toHumanize("0 9 * * *", { locale: "fr" })); // "Quotidien à 9:00"

5. Week of Year Scheduling

import { Schedule, Runner } from "@devloops/jcron";

const runner = new Runner();

// Run on week 33 of the year
const schedule = new Schedule({
  h: "9",
  m: "0",
  woy: "33",
});

runner.addScheduleCron(schedule, () => {
  console.log("Week 33 task");
});

runner.start();

6. React Native Usage

import { Runner } from "@devloops/jcron";
import { useEffect } from "react";

function useScheduler() {
  useEffect(() => {
    const runner = new Runner();

    // Background sync every 15 minutes
    runner.addFuncCron("*/15 * * * *", async () => {
      await syncDataWithServer();
    });

    // Daily cleanup at midnight
    runner.addFuncCron("0 0 * * *", async () => {
      await cleanupOldCache();
    });

    runner.start();

    return () => {
      runner.stop();
    };
  }, []);
}

7. Error Handling & Logging

import { Runner } from "@devloops/jcron";

const runner = new Runner();

// With error handling
runner.addFuncCron("0 9 * * *", async () => {
  try {
    await riskyOperation();
  } catch (error) {
    console.error("Task failed:", error);
    // Implement retry logic or alerting
  }
});

// With custom logging
runner.setLogger({
  error: (msg: string, data?: any) => console.error(msg, data),
  warn: (msg: string, data?: any) => console.warn(msg, data),
  info: (msg: string, data?: any) => console.info(msg, data),
  debug: (msg: string, data?: any) => console.debug(msg, data),
});

runner.start();

🎨 API Reference

Core Functions

getNext(schedule: Schedule | string, from?: Date): Date

Calculate the next run time for a schedule.

import { getNext } from "@devloops/jcron";

const next = getNext("0 9 * * *");
const nextFromDate = getNext("0 9 * * *", new Date("2024-12-25"));

getPrev(schedule: Schedule | string, from?: Date): Date

Calculate the previous run time for a schedule.

import { getPrev } from "@devloops/jcron";

const prev = getPrev("0 9 * * *");

isMatch(schedule: Schedule | string, date: Date): boolean

Check if a date matches a schedule.

import { isMatch } from "@devloops/jcron";

const matches = isMatch("0 9 * * *", new Date("2024-12-25 09:00:00"));

toString(schedule: Schedule | string, options?: HumanizeOptions): string

Convert a schedule to a human-readable string.

import { toString } from "@devloops/jcron";

const description = toString("0 9 * * *");
// "Daily at 9:00 AM"

const turkish = toString("0 9 * * *", { locale: "tr" });
// "Günlük saat 9:00"

Runner Class

The Runner class manages scheduled tasks.

import { Runner } from "@devloops/jcron";

const runner = new Runner();

// Add a function-based cron job
const jobId = runner.addFuncCron("0 9 * * *", () => {
  console.log("Task executed");
});

// Add a Schedule-based cron job
runner.addScheduleCron(schedule, callback);

// Control runner
runner.start();
runner.stop();

// Remove a job
runner.remove(jobId);

Schedule Class

Create schedules using the Schedule class.

import { Schedule } from "@devloops/jcron";

const schedule = new Schedule({
  s: "0", // Seconds (0-59)
  m: "0", // Minutes (0-59)
  h: "9", // Hours (0-23)
  D: "*", // Day of month (1-31, L for last)
  M: "*", // Month (1-12 or JAN-DEC)
  dow: "1-5", // Day of week (0-7 or SUN-SAT, # for nth, L for last)
  Y: "*", // Year (1970-3000)
  woy: "*", // Week of year (1-53)
  tz: "UTC", // Timezone (IANA timezone)
  eod: null, // End of duration (e.g., "E1D")
});

Humanize Options

Customize human-readable output.

interface HumanizeOptions {
  locale?: string; // Language code (default: 'en')
  use24HourTime?: boolean; // Use 24-hour format (default: false)
  dayFormat?: "long" | "short" | "narrow";
  monthFormat?: "long" | "short" | "narrow" | "numeric";
  caseStyle?: "lower" | "upper" | "title";
  verbose?: boolean; // Include verbose descriptions
  includeTimezone?: boolean; // Include timezone info
  includeYear?: boolean; // Include year info
  includeWeekOfYear?: boolean; // Include week of year
  includeSeconds?: boolean; // Include seconds in time
  useShorthand?: boolean; // Use "weekdays"/"weekends" (default: true)
}

🚀 Performance

JCRON delivers exceptional performance through mathematical scheduling and smart caching:

Operation Performance Notes
Simple patterns ~0.002ms Basic cron patterns
Complex patterns ~0.008ms Advanced patterns with nthWeekDay
Timezone conversion 1.68x overhead With caching (was 41x without)
Humanization ~0.5ms With locale caching
Memory usage < 50KB Per Runner instance
CPU idle ~0% Mathematical scheduling, not polling

Optimization Highlights

  • Timezone Cache: Reduces overhead from 41x to 1.68x
  • nthWeekDay Cache: 3.2x speedup for nth weekday patterns
  • Validation Optimization: 1.2x improvement
  • EOD Parsing Optimization: 3.3x faster

For detailed benchmarks, see HUMANIZE_FINAL_REPORT.md.


🌍 Supported Locales

JCRON supports humanization in 10+ languages:

Code Language Example
en English "Daily at 9:00 AM"
tr Turkish "Günlük saat 9:00"
es Spanish "Diario a las 9:00"
fr French "Quotidien à 9:00"
de German "Täglich um 9:00"
pl Polish "Codziennie o 9:00"
pt Portuguese "Diário às 9:00"
it Italian "Giornaliero alle 9:00"
cz Czech "Denně v 9:00"
nl Dutch "Dagelijks om 9:00"

🧪 Testing

# Run all tests
bun test

# Run with coverage
bun test --coverage

# Run specific test suite
bun test tests/01-core-engine.test.ts

# Run linter
npm run lint

# Build and test
npm run build && npm test

Test Coverage

  • ✅ 175+ passing tests
  • ✅ 91.6% coverage
  • ✅ Edge cases covered (DST, leap years, month boundaries)
  • ✅ Performance benchmarks

📊 Bundle Size

JCRON is optimized for minimal bundle size:

Format Size (Gzipped) Use Case
ESM ~45 KB Modern bundlers
CJS ~46 KB Node.js
UMD ~48 KB Browsers
UMD Min ~22 KB CDN usage

Tree-shaking enabled for all formats.


🛠️ Build System

JCRON uses a modern build system with multiple output formats:

# Build all formats
npm run build

# Build specific format
npm run build:rollup  # ESM, CJS, UMD
npm run build:types   # TypeScript declarations

# Watch mode
npm run build:watch

# Analyze bundle size
npm run size
npm run analyze

For detailed build information, see BUILD_SYSTEM.md.


🤝 Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

Development Setup

# Clone the repository
git clone https://github.com/meftunca/jcron.git
cd jcron/node-port

# Install dependencies
bun install

# Run tests
bun test

# Build
npm run build

📄 License

MIT © AI Assistant (Ported from Go)


🙏 Acknowledgments

  • Inspired by the robust Go library jcron
  • Built with TypeScript, Rollup, and modern tooling
  • Community-driven with contributions from developers worldwide

📞 Support


Made with ❤️ by the JCRON Team

⬆ back to top