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

@quilla-be-kit/jobs

v0.2.1

Published

Background-job interfaces + in-process job runner. Register scheduled jobs, run each tick inside a system execution context, shut down cleanly via Disposable.

Readme

@quilla-be-kit/jobs

Background-job contracts and an in-process runner for substrate-grade TypeScript services. Register scheduled jobs, run each tick inside a system execution context, shut down cleanly via Disposable.

pnpm add @quilla-be-kit/jobs

Node 22+, ESM-only.


What's in the box

| Export | What it is | | --- | --- | | BackgroundJob | Interface your jobs implement — name, schedule, execute() | | JobSchedule / JobScheduleType | Schedule union + type constants | | JobRunner | Runner contract — register, stop, drain, dispose | | InProcessJobRunner | Reference implementation — timer-based, single-process |

Zero external runtime deps. Depends on @quilla-be-kit/execution-context, @quilla-be-kit/observability, and @quilla-be-kit/runtime.


Usage

import { AsyncExecutionContextProvider } from '@quilla-be-kit/execution-context';
import { StructuredLoggerFactory } from '@quilla-be-kit/observability';
import {
  type BackgroundJob,
  InProcessJobRunner,
  JobScheduleType,
} from '@quilla-be-kit/jobs';

class HeartbeatJob implements BackgroundJob {
  readonly name = 'infra.Heartbeat';
  readonly schedule = { type: JobScheduleType.Interval, everyMs: 30_000 };

  async execute(): Promise<void> {
    // do work — runs inside a system ExecutionContext (actorType: 'job')
  }
}

const provider = new AsyncExecutionContextProvider();
const logger = /* your Logger */;
const runner = new InProcessJobRunner(provider, logger);

runner.register(new HeartbeatJob());

On shutdown:

await runner.dispose(); // stops timers + awaits in-flight ticks

InProcessJobRunner implements Disposable from @quilla-be-kit/runtime, so you can register it directly with your Runtime and it will be drained as part of normal shutdown.

stop() / drain() / dispose()

The JobRunner contract exposes three distinct lifecycle hooks:

  • stop() — idempotent; stops accepting new ticks. Does not wait for in-flight executions. Returns synchronously.
  • drain() — async; awaits every in-flight tick to complete. Safe to call after stop(); a no-op if nothing is running.
  • dispose() — the shutdown-phase convenience: calls stop() then drain() and returns when everything has settled. This is what you register with Runtime / ShutdownManager.

Split stop() + drain() when you need to stop accepting work before initiating the wait (e.g., drain from multiple runners in parallel with one combined Promise.all(runners.map(r => r.drain()))).


Execution context

Every tick runs inside executionContextProvider.runWithContext(ctx, fn) where ctx is a fresh system context (actorType: 'job', new correlationId). Any downstream code that reads provider.getContext() will see it — including the logger enricher, repository scope checks, event publishers, etc.


Schedule types

Only interval is supported today. The schedule union is extensible — add cron, once, or manual variants when a runner actually implements them, rather than shipping placeholder types a consumer can't trust. The InProcessJobRunner throws at register time on unknown schedule types so additions are a loud, explicit choice.


What this package is not

  • Not a distributed scheduler. Every replica that registers the same job runs it on its own timer — fine for idempotent tick-and-claim jobs (like an outbox forwarder that claims rows atomically), not fine for "run this exactly once per cluster per minute" jobs.
  • Not a cron runtime. interval only, for now.
  • Not a persistent queue. In-process timers, lost on restart.

For cluster-wide cron or persistent-queue semantics, implement JobRunner against your preferred scheduler (Postgres-claimed locks, Redis, Temporal, cloud schedulers, etc.) — the interface is the stable contract.


License

MIT — © Max Martinez.