API Reference

k.jobs

Declare your API's scheduled jobs, with their schedules, inputs, and results.

Alpha

Jobs are new and still settling. k.jobs may change while v2 is in beta, so pin your version if you depend on it.

Declares your API's scheduled jobs. The first argument is the identity every job requires, the credential your scheduler sends. Pass the result to defineConfig under jobs, alongside routes.

jobs.ts
import { z } from 'zod';
import { cron } from 'kizunajs';

export const jobs = k.jobs('scheduler', {
    sendDigests: {
        schedule: cron.daily('05:00'),
        summary: 'Send the daily digest to every user',
        result: z.object({
            sent: z.int(),
        }),
    },
    billing: {
        reconcileInvoices: {
            schedule: cron.every('15m'),
            input: z.object({
                since: z.string(),
            }),
        },
    },
});

Jobs nest to any depth. Because a job carries its own identity, it declares no auth of its own.

Omitting the identity argument declares the jobs public, which leaves anyone who can reach /jobs/run able to trigger them. Pass an identity unless the endpoints are unreachable from outside your network.

See the Scheduled jobs guide for handlers, triggering, and local development.

Job fields

FieldTypeNotes
schedulestring | { cron, timezone }A five-field cron expression, UTC unless a timezone is given. Omit it for a job that is only ever queued from code.
retrynumberHow many attempts a failed run deserves, at least 1. Handed to the transport, which is what retries. Defaults to 1.
inputz.ZodTypeSchema for the payload the job is queued with. Validated on run and queue, and again at the run endpoint.
resultz.ZodTypeSchema for what the job reports on success. Omit it and the job answers 204.
summarystring
descriptionstring
responses{ [status]: ResponseDefinition }Extra responses beyond the synthesized ones.

Synthesized responses

Every job answers with the same set. A scheduler reads the status code to decide whether to retry.

StatusMeaning
200 with result, or 204 withoutDone
422Permanent failure; do not retry
500Unexpected throw; retry
503Transient failure; retry

422, 500, and 503 take an RFC 9457 Problem Details body, so a handler supplies detail plus any extension members.

Schedule helpers

Exported from kizunajs. Each returns a plain cron string.

HelperExpression
cron.every('15m')*/15 * * * *
cron.every('2h')0 */2 * * *
cron.hourly(30)30 * * * *
cron.daily('05:00')0 5 * * *
cron.weekly('mon', '09:00')0 9 * * 1
cron.monthly(1, '05:00')0 5 1 * *

nextRun(schedule, from?) returns the next time a schedule fires, or undefined for a schedule that never can (0 0 30 2 *). nextRuns(schedule, count, from?) returns several.

Reaching a job

Every handler receives a jobs runner shaped like the declaration, with two methods per job. run resolves to what the handler returned, as { status, body }; queue resolves once the job is in line.

src/routes/users.ts
const result = await jobs.billing.reconcileInvoices.run({ since });

await jobs.indexUser.queue({
    input: {
        userId,
    },
    dedupeKey: `index:${userId}`,
    runAt: tomorrow,
});

Input is validated against the job's input schema either way. Where a queued job goes is the transport's business; with none configured it runs in this process.

Validation

k.jobs throws on:

  • an invalid cron expression, naming the field
  • an unknown time zone
  • a retry that is not a whole number, or is below 1
  • a job with a schedule and an input its schema will not accept as empty. A scheduler sends no body, so that job could only ever fail validation

On this page