Expand description
Background jobs (Cloudflare Queues) and scheduled tasks (Cron Triggers).
Rails’ Active Job, on Cloudflare Queues
(in the Workers Free plan since February 2026). The app’s Worker is both
the producer and the consumer of its queues: <app>-jobs, bound as
QUEUE_BINDING, plus one per named queue (<app>-jobs-urgent, bound
as JOBS_URGENT, see queue). A job is a serde value, usually the
app’s Job enum (src/jobs/mod.rs, written by ocre g job), and
dispatch is a plain match in the app’s perform function, not a registry.
A handler enqueues with enqueue, enqueue_in or enqueue_all
(generated jobs wrap it as job.perform_later(&ctx)) and returns as soon
as Cloudflare stored the message; the Worker’s queue event runs it
moments later through consume. Scheduled tasks run from the
scheduled event through cron:
mod jobs {
use ocre::{Ctx, Result};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Job {
SendWelcome { user_id: i64 },
}
pub async fn perform(_ctx: Ctx, job: Job) -> Result<()> {
match job {
Job::SendWelcome { user_id } => {
Ok(())
}
}
}
}
mod schedules {
pub async fn run(_ctx: ocre::Ctx, cron: String) -> ocre::Result<()> {
Ok(())
}
}
// src/lib.rs
#[worker::event(queue)]
async fn queue(batch: worker::MessageBatch<String>, env: worker::Env, _ctx: worker::Context) -> worker::Result<()> {
ocre::jobs::consume(batch, env, jobs::perform).await
}
#[worker::event(scheduled)]
async fn scheduled(event: worker::ScheduledEvent, env: worker::Env, _ctx: worker::ScheduleContext) {
ocre::jobs::cron(event, env, schedules::run).await
}
// A handler
async fn create(axum::extract::State(ctx): axum::extract::State<ocre::Ctx>) -> ocre::Result<&'static str> {
ocre::jobs::enqueue(&ctx, &jobs::Job::SendWelcome { user_id: 1 }).await?;
Ok("created")
}A message is JSON text, {"at": <due unix time>, "job": {"send_welcome": {"user_id": 1}}}.
consume acknowledges a job that returns Ok; drops, with a log line,
one that returns an error another try cannot fix (a 4xx
Error such as NotFound: Rails’ discard_on); retries any other
Err with a growing delay (30 s, 1 min, 3 min, 9 min, 27 min: twice the
time since it was due); and drops a message it cannot decode (an unknown
or changed job), so it is never retried forever. After maxRetries: 5
(cloudflare.config.ts) Cloudflare moves a failing message to the dead-letter
queue <app>-jobs-failed, kept 24 hours. Delivery is at-least-once: write
jobs to be safe to repeat. Every line Ocre logs starts with
LOG_PREFIX or CRON_LOG_PREFIX.
§Free-plan budget (September 2026)
- Queues operations: 10,000 a day. A message costs 3 (write, read, delete), each retry 1 more read, a dead-lettered message 1 more write. Ocre sends one message per job: about 3,300 jobs a day.
- Retention: 24 hours on Free; the last retry comes after about 40 minutes.
- Message size: 128 KB;
enqueuerefuses larger jobs (pass ids).enqueue_allsends 100 messages (256 KB) per call. - Delay: 24 hours at most, on send and on retry;
enqueue_inrefuses longer delays (MAX_DELAY). - Batches: up to 100 messages and 60 s wait; the generated
max_batch_size = 10,max_batch_timeout = 5make one consumer run (one Worker invocation) per 10 jobs. - CPU: 10 ms per invocation, consumer batches and cron runs included:
jobs should be I/O (D1, mail,
fetch); lowermax_batch_sizefor CPU-heavy jobs. - Cron Triggers: 5 per account; run several tasks from one cron.
Structs§
- Budget
- How many calls an invocation may still make: D1 queries,
fetches, KV and R2 operations, as the job counts them. - Queue
- A job queue, from
queue: enqueue on it like on the default queue.
Enums§
Constants§
- CRON_
LOG_ PREFIX - Prefix of every line Ocre logs about Cron Triggers, e.g.
[ocre cron] 0 3 * * * done. - DEFAULT_
QUEUE - Name of the queue
enqueueandenqueue_inuse:default, bound asQUEUE_BINDING. - LOCKS_
TABLE_ SQL - The
job_lockstable oflockandunlock, created by the migration ofocre g job --lock. - LOG_
PREFIX - Prefix of every line Ocre logs about jobs, e.g.
[ocre jobs] send_welcome done. - MAX_
DELAY - Longest delay Cloudflare Queues accepts: 24 hours, for
enqueue_inand retries. - QUEUE_
BINDING - Name of the queue producer binding every Ocre app sends jobs to.
Functions§
- consume
- Runs a batch of queue messages through the app’s
perform; the Worker’squeueentry point. - cron
- Runs the app’s task for the Cron Trigger that fired; the Worker’s
scheduledentry point. - dev_
routes - Development endpoint listing recent jobs, served by
ocre devonly, for tests (Rails’assert_enqueued_withandassert_performed_jobs). - enqueue
- Sends
jobto theJOBSqueue, to run in the background throughconsume. - enqueue_
all - Sends every job of
jobsto theJOBSqueue in as few calls as possible, like Rails’perform_all_later. - enqueue_
in - Sends
jobto theJOBSqueue likeenqueue, to run afterdelay. - lock
- Takes the lock
keyforowneruntilttlseconds from now;falsewhen another owner holds it and it has not expired. The owner holding it takes it again (extending it), so a job that continues in several queue messages keeps its lock from step to step. One D1 write. - queue
- A named queue, for jobs that must not wait behind others:
ocre::jobs::queue(&ctx, "urgent").enqueue(&job). - run_
steps - Runs
stepfromcursorwhilebudgetcovers itscost(the calls one step makes), for work too large for one invocation: a page of rows per step, the next page’s cursor between them (Active Job’s continuations). - unlock
- Releases the lock
keyifownerholds it. One D1 write.