onvibe.run

← All docs

Background tasks

Run heavy or slow work outside the request/response cycle: a request returns immediately and the work happens later, in the background, with retries and de-duplication. Use it for anything that would blow the request budget or that should survive the response: processing an upload, calling an external API, an ingestion pipeline, sending a batch of emails.

A task runs in an ephemeral isolate: the platform loads your app's code, runs one handler, and tears it down. The app does not have to be serving HTTP for a task to run.

Declare handlers with withTasks

Wrap your default HTTP handler with withTasks and pass a map of named task handlers. The default export stays your request handler; onvibe reads the task handlers from it.

import { enqueueTask, withTasks } from "./.onvibe/helpers.ts";

async function handler(req: Request): Promise<Response> {
  const url = new URL(req.url);
  if (req.method === "POST" && url.pathname === "/import") {
    const { fileId } = await req.json();
    const { taskId } = await enqueueTask("process_import", { fileId }, {
      dedupKey: `import:${fileId}`,
    });
    return Response.json({ taskId }, { status: 202 });
  }
  return new Response("hello");
}

export default withTasks(handler, {
  // Each handler gets the payload you passed to enqueueTask. Keep it IDEMPOTENT:
  // a task can run more than once on retry; the source of truth is your database.
  process_import: async ({ fileId }) => {
    const res = await fetch(`https://api.example.com/files/${fileId}`); // external fetch is allowed
    // ...heavy work, write results to your Postgres...
    return { processed: true };
  },
});

Enqueue work with enqueueTask

const { taskId, deduplicated } = await enqueueTask("process_import", { fileId }, {
  dedupKey: "import:42",  // optional: won't enqueue a second task while one with this key is active
  maxAttempts: 3,         // optional: retries on failure (exponential backoff)
});

Check status with checkTask

const status = await checkTask(taskId);
// null if no such task, else:
// { status: "pending" | "running" | "done" | "failed", result?: unknown, error?: string }
if (status?.status === "done") {
  // status.result is whatever the task handler returned
}

Notes

Read this page as Markdown (best for LLMs) · plain text
onvibe.run · home · all docs