Runnel 2.8: replay any workflow from a failed step.Read the release

Skip to content
Runnel
Documentation

    Docs menu

    Core concepts

    Jobs, runs, attempts, workflows and steps, schedules, workers and environments: the handful of ideas the rest of the docs build on.

    Runnel has a small vocabulary. Once these terms are clear, the guides and the API reference read as variations on them.

    Jobs and runs

    A job is a named function in your code, such as send-invoice, with its options: retries, timeout, concurrency. The name is the job’s identity. Keep it stable; renaming a job creates a new one.

    A run is one execution of a job with one payload. Every call to enqueue, every schedule tick and every POST /v1/runs creates a run with an id like run_01JB7X2K9Q4MZ8. A run moves through these statuses:

    StatusMeaning
    queuedStored and waiting for a worker, or delayed until scheduled_for.
    runningA worker has it and is running an attempt.
    retryingAn attempt failed and the next one is queued after a backoff.
    succeededAn attempt returned. Its return value is the run’s output.
    failedThe last attempt failed, or the job threw a fatal error.
    cancelledCancelled from the dashboard, the CLI or the API.

    Attempts

    An attempt is one try at a run. When an attempt throws or times out, Runnel waits and tries again, up to the job’s retries.attempts. Attempts belong to the run: they share its id, its payload and its log, and they do not count as extra runs on your bill. See Retries and timeouts.

    Workflows and steps

    A workflow is a job whose function is split into named steps:

    const order = await ctx.step('reserve-stock', () => inventory.reserve(input.items));
    await ctx.step('charge-card', () => payments.charge(input.customerId, order.total));
    await ctx.step('send-confirmation', () => mailer.confirm(order.id));

    When a step finishes, its result is stored. If a later step fails and the run is retried, finished steps return their stored result instead of running again, so the card is charged once. Workflows can also wait: ctx.sleep for a duration, ctx.waitForEvent for something to happen elsewhere. See Workflows.

    Schedules

    A schedule creates a run of a job on a cron expression, in a time zone. Schedules are defined in code and registered when you deploy. Each tick is an ordinary run, so retries and logs work the same way. See Schedules.

    Workers

    A worker is a process you run that has your jobs loaded. It connects out to Runnel, asks for runs of the jobs it knows, runs them and reports the result. You can run as many workers as you like; Runnel hands each run to one of them. If a worker dies mid-run, its runs are given to another worker and counted as a failed attempt.

    Note Runnel only ever stores the payload, the output, the step results and the logs. Your code, your database and your credentials stay on your infrastructure.

    Projects, environments and versions

    A project groups the jobs of one application. Each project has environments, by default development, staging and production, with separate runs, schedules and API keys. Each runnel deploy creates a numbered version of the job definitions in one environment (v42), and every run records the version it was enqueued under.

    Idempotency

    Pass an idempotencyKey when you enqueue, and Runnel returns the existing run instead of creating a second one if the same key arrives again within 24 hours. Use it whenever an enqueue might be repeated, for example from a webhook handler that its sender retries.

    await sendInvoice.enqueue({ invoiceId: 'inv_8812' }, { idempotencyKey: 'invoice:inv_8812' });

    Steps give you idempotency inside a run; idempotency keys give it to you at the door.

    Edit this page