Jobs & cron
Run background work and scheduled tasks with the built-in queue.
Updated
Railbase has a built-in background job runner and scheduler — no Redis, no separate worker process. Use it for anything that shouldn't block a request: sending email, generating documents, sweeping expired data.
Define a job
Register a handler under a kind at boot, then enqueue work against that kind at
runtime. The registry (and the store) come up during App.Run, so register from
inside OnBeforeServe — calling app.Jobs() directly in the ExecuteWith
callback returns nil (the subsystem doesn't exist yet):
import "github.com/railbase/railbase/pkg/railbase/jobs"
cli.ExecuteWith(func(app *railbase.App) {
app.OnBeforeServe(func(_ chi.Router) {
// Register: maps a "kind" to a handler. j.Payload is the raw
// JSON the enqueuer passed.
app.Jobs().Register("email.welcome", func(ctx context.Context, j *jobs.Job) error {
return sendWelcome(ctx, j.Payload)
})
})
})
// Enqueue (e.g. from a hook or REST handler — any time after boot):
_, err := app.JobsStore().Enqueue(ctx, "email.welcome",
map[string]any{"user_id": id},
jobs.EnqueueOptions{Delay: 30 * time.Second})
Jobs retry on failure (default 5 attempts). Return jobs.ErrPermanent to fail
without retrying.
Inspect jobs from the CLI
railbase jobs list
railbase jobs show <id>
railbase jobs run-now <id>
railbase jobs cancel <id>
railbase jobs recover # requeue jobs stuck in "running"
Note
Like every command that opens the vault, these need exclusive access to the data file — stop the server first, or you'll get "vault: file is locked by another process". To inspect and manage jobs on a running instance, use the admin console instead (see below).
Built-in maintenance jobs
The core ships a set of housekeeping jobs, pre-scheduled out of the box (see
the _cron collection in the admin to adjust or disable them):
| Kind | Default schedule | What it does |
|---|---|---|
cleanup_sessions / cleanup_admin_sessions / cleanup_record_tokens |
nightly | drops expired credentials |
cleanup_exports |
nightly | removes finished export artifacts |
cleanup_jobs |
nightly | prunes completed/failed _jobs rows so the queue stays fast |
cleanup_notifications |
nightly | deletes read notifications older than 30 days and any older than 90 |
cleanup_orphan_files |
weekly | reserved — file-orphan sweep (pending) |
audit_seal / audit_archive |
daily | seals and archives the audit trail |
retry_failed_welcome_emails |
every 30 min | re-queues failed welcome emails (48 h window) |
Unread-but-recent notifications are never touched, and active jobs are never pruned — retention only ever removes terminal, aged rows.
Schedule recurring work
Persisted schedules are managed with railbase cron (standard 5-field cron
expressions):
railbase cron upsert nightly-report "0 3 * * *" report.generate
railbase cron list
railbase cron run-now nightly-report
railbase cron disable nightly-report
You can also schedule from a JavaScript hook:
$app.cronAdd("nightly", "0 3 * * *", () => { /* … */ });
Tip
Scheduled backups are just a built-in job kind — you can manage them here or from the admin's Backups screen. See Backups & restore.
The admin console shows the schedule table and lets you run, enable/disable, or edit entries — see Operating from the admin.