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

imagic-scheduler

v1.0.1

Published

Task scheduler with inProcess guard, per-task intervals, and execution timeouts

Readme

imagic-scheduler

Task scheduler with inProcess guard, per-task intervals, and execution timeouts.

Install

npm install imagic-scheduler

Quick Start

import Scheduler from 'imagic-scheduler'

const scheduler = new Scheduler({
    onError: (name, err) => console.error(`[${name}] failed:`, err),
    onTimeout: (name) => console.warn(`[${name}] timed out`),
})

scheduler
    .schedule('syncPrices', async () => {
        await fetchAndStorePrices()
    }, { interval: 60_000, timeout: 30_000 })
    .start()

API

new Scheduler(options?)

new Scheduler(options?: {
    tickInterval?: number
    onError?: (name: string, err: Error) => void
    onTimeout?: (name: string) => void
})

| Option | Type | Default | Description | |--------|------|---------|-------------| | tickInterval | number | 1000 | How often (ms) the internal clock checks tasks | | onError | function | console.error | Called with (taskName, error) when a task throws | | onTimeout | function | console.warn | Called with (taskName) when a task exceeds its timeout |


scheduler.schedule(name, fn, options)

scheduler.schedule(
    name: string,
    fn: () => Promise<void>,
    options: {
        interval: number
        timeout?: number
        runImmediately?: boolean
    }
): this

Registers a named task for recurring execution.

| Option | Type | Default | Description | |--------|------|---------|-------------| | interval | number | required | How often (ms) to run the task | | timeout | number | 10000 | After this many ms, marks the task as not-in-process and calls onTimeout; the underlying promise continues (orphaned) | | runImmediately | boolean | true | If true, the first run is scheduled for the next tick; if false, the first run is scheduled after interval ms |

Returns this for chaining.

Throws Error if the task name is already registered. Throws TypeError if fn is not a function or interval is not a positive number.


scheduler.unschedule(name)

scheduler.unschedule(name: string): this

Removes a task by name. No-op if the task is not registered. Returns this.


scheduler.start()

scheduler.start(): this

Starts the internal tick loop. Idempotent — calling start() on an already-running scheduler has no effect. Returns this.


scheduler.stop()

scheduler.stop(): this

Stops the internal tick loop. Idempotent. Does not abort any currently running task. Returns this.


scheduler.isRunning()

scheduler.isRunning(): boolean

Returns true if the scheduler is currently running.


scheduler.getStatus()

scheduler.getStatus(): Record<string, {
    inProcess: boolean
    interval: number
    timeout: number
    nextExecuteTime: number
    runId: number
}>

Returns a snapshot of all registered tasks. Each key is a task name.

| Field | Description | |-------|-------------| | inProcess | true if the task is currently executing | | interval | Configured repeat interval in ms | | timeout | Configured execution timeout in ms | | nextExecuteTime | Timestamp (ms) when the task will next run | | runId | Monotonically incrementing counter for the current/last run |


createScheduler(options?)

createScheduler(options?: ConstructorParameters<typeof Scheduler>[0]): Scheduler

Factory function — equivalent to new Scheduler(options). Named export for use without new.

import { createScheduler } from 'imagic-scheduler'

const scheduler = createScheduler({ tickInterval: 500 })

Error Handling

| Situation | Behavior | |-----------|----------| | Task function throws | onError(name, err) is called; inProcess is cleared; task is not unscheduled | | Task exceeds timeout | onTimeout(name) is called; inProcess is cleared; the promise continues running (orphaned) | | Duplicate name in schedule() | Throws Error synchronously | | fn is not a function | Throws TypeError synchronously | | interval is not a positive number | Throws TypeError synchronously |

Errors in onError or onTimeout callbacks are not caught — keep them safe.

Examples

See examples/basic.js for a runnable demonstration.

node examples/basic.js

License

MIT