Skip to content
BACKFILLS & BACKGROUND JOBSOPEN-SOURCE TYPESCRIPT SDK

Hard limits
for the jobs
you run.

Captor puts execution contracts around backfills and background jobs. Set per-run limits, save completed progress, verify the outcome, and inspect what happened.

npm install captar
Product: Captor · npm package: captar · Node.js 22+
RUNTIME / 001API SYNC / INTERACTIVE DEMO
REQUESTS USED4/4Limit enforced
01
02
03
04
05
06
Request 5 blocked before execution.
RUNS INSIDE YOUR EXISTING STACK
cronqueuesscriptsworkflows

A successful exit
isn’t the whole story.

A job can return normally after doing too much,
or fail with no trustworthy place to restart.

CODE THAT SETS THE RULES

An ordinary job.
With a contract.

Add Captor where the side effects happen. Reserve capacity before work, commit it after success, and report a metric for the outcome check. These examples use the published captar package.

Run the quickstart See the fresh-process recovery demo
customer-repair.tsTypeScript
import { run } from 'captar';

const customers = [{ id: 1 }, { id: 2 }, { id: 3 }];
const repaired = new Set<number>();

const { receipt } = await run(
  'customer-repair',
  {
    limits: { resources: { 'db.writes': 3 } },
    outcome: { 'records.processed': { equals: customers.length } },
  },
  async (execution) => {
    for (const customer of customers) {
      const write = execution.reserve('db.writes', 1);
      repaired.add(customer.id); // replace with awaited write
      execution.commit(write);
    }
    execution.metric('records.processed', repaired.size);
  }
);

console.log(receipt.status, receipt.resources['db.writes']);
A complete local example: the fourth guarded write would fail before it starts. Replace the Set with an awaited, idempotent database write.Run the quickstart

For work that can’t
run without a boundary.

Run it from cron, BullMQ, Temporal, a CI job, or a plain Node process.

01 / USE CASE

Data backfills

Batch a large update, cap writes per invocation, and resume from the last saved offset.

db.writes
02 / USE CASE

Repair scripts

Keep one-off fixes inside an explicit write limit and check the result before calling them done.

records.processed
03 / USE CASE

API syncs

Bound outgoing fetch attempts when an external API or retry loop behaves unexpectedly.

http.requests
04 / USE CASE

Recurring workers

Put a per-run contract around the work your existing cron or queue worker starts.

per-run policy
LOCAL BY DEFAULT

Your runner starts it.
Captor bounds it.

Captor lives inside your Node application. It checks operations you route through the SDK, then produces an execution receipt. Use runStored or a stored backfill to keep receipts and checkpoints in local JSONL or SQLite.

01Your runnerStarts the job
02Captor SDKChecks the contract
03Your workReturns a receipt

The platform can inspect a receipt file you choose to import; it does not execute jobs or automatically collect execution receipts.

EXECUTION RECEIPT EXAMPLE
customer-repair succeeded
db.writes3 / 3committed / limit
records.processed3outcome metric
violations0contract checks
Save locally when a store is supplied.
THE IMPORTANT DETAILS

Know the boundary.

Limits are enforced where your code calls Captor or uses its supported adapters. Deadlines send an AbortSignal; the underlying work must honor cancellation. Captor cannot undo an already completed side effect.

Read the execution model

Common questions

Does Captor replace my job runner?

No. Keep your existing cron, queue, workflow engine, or Node process. Captor runs inside the application code that performs the work.

Does it automatically count every write and request?

Only operations routed through Captor count. Use reserve/commit in your code, boundedFetch, or the supported Prisma query guard. Work that bypasses those boundaries is not automatically metered.

Can a resumed backfill repeat a write?

Yes. A failure between an external side effect and its saved checkpoint can repeat that work. Use stable source ordering, idempotent writes, and transactions where appropriate. Each resumed invocation has a fresh limit.

Do I need an account or hosted platform?

No. The SDK and JSONL or SQLite receipt stores work locally. The optional platform supports manual import and inspection of receipt files; it does not remotely run your jobs.

Why is the npm package named captar?

Captor is the product name. The published npm package and the import path are currently captar. The package supports Node.js 22 and newer.

START WITH ONE REAL JOB

Put a limit on your next backfill.

Install the open-source SDK, run a local example, then test it against a small, representative workload.