OqronKitOqronKit

Quick Start

Build your first crash-safe background job in 2 minutes

Quick Start

This guide walks you through the three most common OqronKit patterns — a simple task queue, a distributed worker, and a cron schedule.

1. Bootstrap OqronKit

First, define your background triggers. Then, instantiate Oqron and call start(). OqronKit reads your definitions globally and enables the corresponding engines automatically.

index.ts
import { Oqron } from "oqronkit";

// Import your definition files so they are registered before start:
import "./jobs/email-queue.js";
import "./jobs/billing.js";
import "./jobs/crons.js";

const oqron = new Oqron({
  mode: "memory", // Use 'redis' or 'redis-postgres' in production
});

await oqron.start();

In production, add a backend and identify your deployment — project scopes all state (services sharing queues must share it), environment separates stages on shared infrastructure:

index.ts (production)
const oqron = new Oqron({
  mode: "redis-postgres",
  redis: process.env.REDIS_URL!,
  postgres: process.env.DATABASE_URL!,
  project: "shop",
  environment: process.env.NODE_ENV ?? "development",
});

2. Simple Task Queue

The fastest way to get started. Publisher and consumer live in the same process.

jobs/email-queue.ts
import { Queue } from "oqronkit";

export const emailQueue = Queue<{ to: string; body: string }>({
  name: "send-email",
  handler: async (ctx) => {
    console.log("Sending email to:", ctx.data.to);
    await sendEmail(ctx.data.to, ctx.data.body);
    return { sent: true };
  },
});

// Enqueue a job (can be called anywhere after module execution)
await emailQueue.add({
  to: "user@example.com",
  body: "Welcome to OqronKit!",
});

3. Distributed Worker

For production — separate your API servers (senders) from your worker servers (processors).

jobs/billing.ts
import { Queue, Worker } from "oqronkit";

// Publisher-only queue (no handler) — lives on API nodes
export const billingQueue = Queue<{ userId: string; amount: number }>({
  name: "billing",
});

// Consumer-only worker — lives on worker nodes
export const billingWorker = Worker<{ userId: string; amount: number }>({
  topic: "billing",
  handler: async (ctx) => {
    await chargeBilling(ctx.data.userId, ctx.data.amount);
    return { charged: true };
  },
});
api-server.ts
// Push a job from your API route
import { billingQueue } from "./jobs/billing.js";

app.post("/api/charge", async (req, res) => {
  await billingQueue.add({ userId: req.body.userId, amount: 99 });
  res.json({ status: "queued" });
});

4. Cron Schedule

Run background jobs on a schedule.

jobs/crons.ts
import { Cron } from "oqronkit";

export const cleanup = Cron({
  name: "daily-cleanup",
  expression: "0 0 * * *", // Every day at midnight
  timezone: "America/New_York",
  handler: async (ctx) => {
    const deleted = await db.deleteOldRecords();
    ctx.log.info(`Cleaned up ${deleted} records`);
  },
});

5. Production Touches

Three options turn the examples above production-grade:

jobs/billing-report.ts
Cron({
  name: "nightly-billing",
  expression: "0 0 * * *",

  durable: true, // crash-safe fires: each slot becomes a
  // deduplicated job with retries + reclaim
  retries: { max: 3, strategy: "exponential", baseDelay: 5_000 },

  environments: ["production"], // never fires in dev/staging deployments

  handler: runBilling,
});
  • durable: true — a crash mid-handler is retried on another node instead of lost. Use for billing, emails, data mutations. (Scheduler → Durable fires)
  • environments — the definition is inert outside the listed environments; works on every module. (Environments)
  • retries + dead letters — exhausted retries land in an inspectable, resendable DLQ. (Crash Safety)

What's Next?

On this page