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

@acegalaxy/scheduler-runtime

v0.1.2

Published

Notion-backed cron catalog for Node.js — see all your scheduled jobs in one Notion table, with auto-tracked status, last run, and errors. Pluggable cron adapter + reporter + status tracker.

Readme

@acegalaxy/scheduler-runtime

npm version npm downloads License: MIT Node

Notion-backed cron catalog — see all your scheduled jobs in one Notion table, with status, last run, and errors auto-tracked. An alternative to BullMQ-only / Inngest when you want a human-readable, ops-friendly source of truth that lives where your team already works.

License: MIT Node

Why

  • Visibility for ops — every cron in the company shows up in one Notion DB. PM, ops, and on-call all see the same row.
  • No new dashboard. Status / last run / errors flow into Notion fields you can filter, sort, comment on.
  • Bring-your-own cron. Works on top of node-cron, PM2 cron_restart, or any adapter exposing .schedule().
  • Fire-and-forget catalog sync. Notion failures NEVER bubble into your jobs.
  • Project-agnostic. Cron adapter, error reporter, status tracker, Notion DB id + token are ALL injected. The runtime hardcodes nothing.

What's in the box

  • Overlap lock — same-job re-entry skipped
  • Report lock — critical reports pause background jobs
  • Pluggable error reporter — project injects Telegram routing / cooldown
  • Pluggable status tracker — project injects file/DB persistence
  • Notion catalog auto-sync — fire-and-forget upsert per registration

Install

npm install @acegalaxy/scheduler-runtime node-cron

Quick start

1. Register a cron job

const cron = require("node-cron");
const runtime = require("@acegalaxy/scheduler-runtime");

// One-time configuration
runtime.configure({
  cronAdapter: cron,                                  // node-cron or compatible
  reporter: (label, err) => myTelegramAlert(label, err),
  statusTracker: (name, status, ms) => myStatusFile(name, status, ms),
  catalog: {
    token: process.env.NOTION_API_KEY,
    dbId: process.env.NOTION_DB_SCHEDULER_CATALOG,
    project: "nexus",                                 // slug for filtering
    host: "PROD",                                     // or "LOCAL"
    tz: "Asia/Ho_Chi_Minh",
    enabled: () => process.env.DOCKER_CONTAINER === "1",
    alertOnce: async (kind, name, msg) => myTelegramAlert(`Catalog ${kind}`, msg),
  },
});

// Register schedulers
runtime.scheduleJob("morning-check", "30 8 * * *", runMorningCheck);
runtime.scheduleJob("daily-report",  "0 18 * * *", runDailyReport, { isReport: true });

2. View status in Notion

Open your catalog DB. Each registered job appears as a row with Name, Cron, Project, Host, Source File, Schedule TZ, and Last Reviewed auto-populated. Add views per project / per host as needed.

3. Get alerted on failure

Your injected reporter(label, err) is called whenever a wrapped job throws. Pipe it to Telegram, Slack, PagerDuty — whatever your team already uses. The status tracker also flips the row to failed so on-call can triage from Notion directly.

API

configure(opts)

| Field | Type | Notes | |---|---|---| | cronAdapter | object | Must expose .schedule(expr, fn, opts). Required for scheduleJob(). | | reporter | (label, err) => void | Called when wrapped fn throws. Default = console.error. | | statusTracker | (name, status, durationMs?) => void | status is "running" / "done" / "failed". Default = no-op. | | catalog | object | See catalog config below. Skipped if missing token/dbId/project. |

catalog config

| Field | Type | Notes | |---|---|---| | token | string | Notion integration bearer. | | dbId | string | Notion DB ID (with or without dashes). | | project | string | Project slug, e.g. "nexus". Used for Project select column. | | host | string | "PROD" or "LOCAL". Project decides. | | tz | string | Default "Asia/Ho_Chi_Minh". | | enabled | () => boolean | Gating predicate. Default () => true. Use to PROD-gate. | | alertOnce | async (kind, name, msg) => void | Optional. Called once per error kind to surface drift. |

scheduleJob(name, schedule, fn, options?)

Wraps fn, registers via cronAdapter, fires catalog upsert.

  • options.isReport — if true, uses report-lock wrapper (pauses background jobs)
  • options.timezone — default "Asia/Ho_Chi_Minh"

Returns whatever the cron adapter's schedule() returns.

createBackgroundJob(name, fn) / createReportJob(name, fn)

Standalone wrappers for direct use (e.g. PM2 cron_restart one-shots that don't go through node-cron). Returns async () => void.

isReportRunning()

Boolean — true while a report-job is in-flight.

Notion DB schema

Project must create a Notion DB with these properties (auto-managed):

| Property | Type | Auto/Manual | |---|---|---| | Name | title | auto | | Project | select | auto | | Cron | rich_text | auto | | Host | select (PROD/LOCAL) | auto | | Source File | rich_text | auto | | Schedule TZ | select | auto | | Last Reviewed | date | auto | | Status | select (Active/Paused/...) | auto on create only | | Description | any | manual (preserved) | | Type | any | manual (preserved) | | Notes | any | manual (preserved) | | Target | any | manual (preserved) |

The DB is shared across projectsProject column distinguishes rows. Filter views per project as needed.

Error handling philosophy

  • Wrapped fn errors → reporter(label, err) + statusTracker(name, "failed", ms) + lock released
  • Catalog upsert errors → logged + alertOnce(kind, name, msg) if configured. NEVER bubbles into caller.
  • Reporter / tracker errors → swallowed (logged to stderr). Never crash the scheduler.

Testing

npm test

15 unit tests cover wrappers, locks, catalog upsert/patch/skip, error classification.