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

@bklarjs/cron

v1.0.0

Published

A minimal, robust cron job scheduler for the bklar framework.

Readme

@bklarjs/cron ⏰

NPM Version License: MIT

A minimal, robust, and type-safe cron job scheduler for the bklar framework.

This plugin allows you to define scheduled tasks directly within your application middleware, automatically manages their lifecycle, and exposes runtime controls (start/stop) to your route handlers via the application context.


✨ Features

  • 📅 Standard Cron Syntax: Supports standard 5-field and 6-field (seconds) cron patterns.
  • 🎛️ Context Integration: Jobs are registered to ctx.state.cron, allowing you to control them programmatically from your API.
  • 🛡️ Overlap Protection: Built-in support to skip scheduled runs if the previous execution hasn't finished.
  • Lightweight: Designed for in-memory, single-instance workloads without heavy external dependencies.
  • 🧩 TypeScript Ready: Full type support for configuration and job controls.

📦 Installation

This package is designed to work with bklar.

bun add bklar @bklarjs/cron

🚀 Quick Start

  1. Register the middleware with your job configuration.
  2. Access the job in your routes via ctx.state.cron.
import { Bklar } from "bklar";
import { cron } from "@bklarjs/cron";

const app = Bklar();

// 1. Register a background task
app.use(
  cron({
    name: "heartbeat",
    pattern: "*/5 * * * * *", // Run every 5 seconds
    run: () => {
      console.log("💓 App is alive at", new Date().toISOString());
    },
  })
);

// 2. Control the job via an endpoint
app.get("/status", (ctx) => {
  // Access the job by its name
  const job = ctx.state.cron.heartbeat;

  return ctx.json({
    isRunning: job.isRunning(),
    nextRun: job.nextRun(),
  });
});

app.listen(3000);

⚙️ Configuration Options

The cron(config) factory accepts the following options:

| Option | Type | Default | Description | | :-------------- | :------------------ | :-------------- | :----------------------------------------------------------------------------------------- | | name | string | Required | A unique identifier for the job. Used to access the job in ctx.state.cron. | | pattern | string | Required | The cron expression (e.g., * * * * * or */5 * * * * *). | | run | () => void | Required | The function to execute. Can be asynchronous. | | timezone | string | Local | IANA timezone string (e.g., America/New_York or Europe/London). | | autoStart | boolean | true | Whether the job should start immediately upon registration. | | overlap | "allow" \| "skip" | "allow" | Determines behavior if a scheduled run triggers while the previous run is still executing. | | onError | (err) => void | console.error | Callback for handling errors thrown inside the run function. |

🕹️ Controlling Jobs

Every registered job is exposed in the ctx.state.cron object. The job interface provides the following methods:

interface CronJobControl {
  start(): void; // Resumes/Starts the schedule
  stop(): void; // Pauses/Stops the schedule
  isRunning(): boolean; // Returns true if the schedule is active
  nextRun(): Date | null; // Returns the next scheduled execution date
}

Example: Stopping a Job via API

app.post("/jobs/:name/stop", (ctx) => {
  const { name } = ctx.params;
  const job = ctx.state.cron[name];

  if (!job) {
    return ctx.json({ error: "Job not found" }, 404);
  }

  job.stop();
  return ctx.json({ message: `Job '${name}' has been stopped.` });
});

🛡️ Handling Overlaps

If you have a long-running task (e.g., database backup, heavy report generation) and you want to ensure it never runs concurrently with itself, set overlap to "skip".

app.use(
  cron({
    name: "nightly-backup",
    pattern: "0 3 * * *", // Every day at 3:00 AM
    overlap: "skip", // If the previous backup is still running, skip this one
    run: async () => {
      console.log("Starting backup...");
      await performHeavyBackup();
      console.log("Backup finished.");
    },
  })
);

🧩 Patterns Helper

For convenience, we provide a Patterns object with common cron expressions to avoid looking up syntax.

import { cron, Patterns } from "@bklarjs/cron";

app.use(
  cron({
    name: "cleanup",
    pattern: Patterns.EVERY_DAY_AT_MIDNIGHT,
    run: () => console.log("Cleaning up temp files..."),
  })
);

Available Patterns:

  • EVERY_SECOND: * * * * * *
  • EVERY_MINUTE: * * * * *
  • EVERY_HOUR: 0 * * * *
  • EVERY_DAY_AT_MIDNIGHT: 0 0 * * *
  • EVERY_MONDAY: 0 0 * * 1
  • EVERY_MONTH: 0 0 1 * *

⚠️ Production Notes

In-Memory Behavior

@bklarjs/cron runs in-memory.

  1. Persistence: If you restart your server, the job history and "running" state resets (though autoStart defaults to true).

  2. Clustering: If you run multiple instances of your bklar application (e.g., using PM2 clusters or Kubernetes replicas), each instance will run its own copy of the cron job.

    For distributed systems where a job must run exactly once across a cluster, consider using an external job queue (like Redis/BullMQ) instead of this middleware.

Error Handling

By default, errors thrown inside the run function are caught and logged to console.error to prevent crashing the main application thread. You can customize this behavior:

app.use(
  cron({
    name: "risky-job",
    pattern: "* * * * *",
    run: () => {
      throw new Error("Something went wrong");
    },
    onError: (err) => {
      // Send to Sentry, Datadog, etc.
      myLogger.error("Cron job failed", err);
    },
  })
);

🤝 Contributing

Contributions are welcome! Please open an issue or submit a Pull Request to the main bklar repository.

📄 License

This project is licensed under the MIT License.