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 🙏

© 2025 – Pkg Stats / Ryan Hefner

redis-distro-scheduler

v0.3.2

Published

Distributed, Redis-backed cron scheduler with multi-tenant guardrails and jitter, designed for Node.js 24 and TypeScript.

Readme

redis-distro-scheduler

Distributed, Redis-backed cron scheduler with multi-tenant guardrails and jitter,
designed for Node.js 24 and TypeScript.

  • ✅ Works across multiple pods / processes (Redis lock)
  • Dynamic create / update / delete of schedules (no restart)
  • Per-tenant guardrails (limit schedules, enforce min interval)
  • Jitter to avoid thundering herd on the same second
  • ✅ First-class TypeScript support

Installation

npm install redis-distro-scheduler
# or
yarn add redis-distro-scheduler

Basic Concepts

  • A schedule is a row in your DB (per customer) that defines:
    • cronExpression
    • timezone
    • report payload (what to generate, recipients, filters, etc.)
  • Each schedule is executed by the library via a Scheduler instance.
  • SchedulerManager keeps all schedulers in memory and reacts to:
    • initial load from DB
    • create / update / delete events (e.g. via Redis Pub/Sub)
  • Redis is used as a distributed lock, so only one pod runs a job per tick.

Quick Start

1. Define your ScheduleRecord source (DB)

import type { ScheduleRecord } from "redis-distro-scheduler";

// Example structure (you likely already have something similar in your DB)
// interface ScheduleRecord {
//   id: string;
//   customerId: string;
//   name: string;
//   cronExpression: string;
//   timezone?: string;
//   payload: any;
//   enabled: boolean;
// }

2. Create a SchedulerManager in each app pod

import { SchedulerManager, type ScheduleRecord } from "redis-distro-scheduler";

async function fetchAllEnabledSchedules(): Promise<ScheduleRecord[]> {
  // SELECT * FROM report_schedules WHERE enabled = 1;
  return [];
}

async function callback(schedule: ScheduleRecord): Promise<void> {
  // Your business logic:
  //  - Generate report
  //  - Send email
  //  - Store file / etc.
  console.log("Running report for schedule", schedule.id);
}

const manager = new SchedulerManager({
  redisUrl: process.env.REDIS_URL,
  callback,
  defaultMaxJitterMs: 30_000, // spread executions up to 30s per schedule
});

// On startup
await manager.loadInitialSchedules(await fetchAllEnabledSchedules);

3. React to create / update / delete via Redis Pub/Sub (or any bus likr rabbitmq/sqs etc.)

type ScheduleEvent =
  | { type: "created" | "updated"; schedule: ScheduleRecord }
  | { type: "deleted"; scheduleId: string };

await sub.subscribe("report-schedules");

sub.on("message", (_channel, msg) => {
  const event: ScheduleEvent = JSON.parse(msg);

  switch (event.type) {
    case "created":
    case "updated":
      manager.upsertSchedule(event.schedule);
      break;
    case "deleted":
      manager.removeSchedule(event.scheduleId);
      break;
  }
});

4. Tenancy guardrails

Use ensureMinimumInterval to enforce per-tenant cron frequency limits:

import {
  DEFAULT_TENANT_GUARDRAILS,
  ensureMinimumInterval,
} from "redis-distro-scheduler";

async function validateScheduleBeforeSave(input: {
  cronExpression: string;
  timezone?: string;
  customerId: string;
}) {
  // Example: enforce minimum interval
  ensureMinimumInterval(
    input.cronExpression,
    input.timezone,
    DEFAULT_TENANT_GUARDRAILS.MIN_INTERVAL_MINUTES
  );

  // Example: count active schedules in DB and compare to
  // DEFAULT_TENANT_GUARDRAILS.MAX_ACTIVE_SCHEDULES_PER_CUSTOMER
}

5. Jitter and locking

  • Each schedule has a dedicated Redis key:

    redis-distro-scheduler:report:<scheduleId>:lock
  • At each cron tick:

    1. All pods try SET key "locked" NX PX <ttl>.
    2. Only one pod gets "OK" and runs the job.
    3. That pod waits a deterministic jitter based on schedule ID, up to maxJitterMs.
    4. It then executes your callback(schedule) callback.

API Overview

SchedulerManager

High-level orchestrator for many schedules.

const manager = new SchedulerManager(callback: async (schedule) => {
    // ...
  }, {
  redisUrl: process.env.REDIS_URL
});

await manager.loadInitialSchedules(fetchAllEnabled);

// React to events:
manager.upsertSchedule(schedule);  // create or update
manager.removeSchedule(id);        // delete / disable

Tenant guardrails utilities

import {
  DEFAULT_TENANT_GUARDRAILS,
  ensureMinimumInterval,
  type TenantGuardrailsConfig,
} from "redis-distro-scheduler";

Node.js and TypeScript

  • Written in TypeScript, compiled to ESM + CJS.
  • Tested with Node.js 24.
  • Ships with type declarations (.d.ts).

Testing

This package uses Vitest for unit tests.

npm test

License

MIT