Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Core Concepts

Graphile Worker RS is a PostgreSQL-backed job queue for Rust applications. The core mental model is:

  1. Your application describes work as typed tasks.
  2. It adds jobs for those tasks into PostgreSQL.
  3. A worker fetches runnable jobs, executes the matching task handler, and records the result back in PostgreSQL.

The database is the coordination point. Jobs, task metadata, queue state, worker state, retry metadata, and scheduling data live in the Graphile Worker schema, which defaults to graphile_worker.

The Main Pieces

Tasks

A task is the Rust type that defines what a job does. It implements TaskHandler, provides a stable task identifier, accepts a serializable payload, and contains the async run method for the work.

use graphile_worker::{IntoTaskHandlerResult, TaskHandler, WorkerContext};
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
struct SendEmail {
    to: String,
    subject: String,
}

impl TaskHandler for SendEmail {
    const IDENTIFIER: &'static str = "send_email";

    async fn run(self, _ctx: WorkerContext) -> impl IntoTaskHandlerResult {
        println!("Sending email to {}", self.to);
        Ok::<(), String>(())
    }
}

Register task handlers on WorkerOptions before starting the worker:

let worker = graphile_worker::WorkerOptions::default()
    .define_job::<SendEmail>()
    .pg_pool(pg_pool)
    .init()
    .await?;

For more detail, see Tasks and Payloads.

Jobs

A job is a stored request to run a task. It includes the task identifier, payload, state, and execution metadata. Job specifications can also carry options such as priority, retry behavior, scheduling information, and queue selection.

Jobs are stored in PostgreSQL, so application processes can enqueue work and worker processes can execute it independently. WorkerUtils provides utility operations for managing jobs, such as adding, removing, and rescheduling them.

Workers

A worker is the runtime process that polls PostgreSQL, locks runnable jobs, and executes registered handlers with the configured concurrency. Graphile Worker RS uses PostgreSQL features such as SKIP LOCKED for efficient job fetching and LISTEN/NOTIFY for low-latency wakeups.

graphile_worker::WorkerOptions::default()
    .concurrency(5)
    .define_job::<SendEmail>()
    .pg_pool(pg_pool)
    .init()
    .await?
    .run()
    .await?;

Workers also own lifecycle concerns such as graceful shutdown. Optional recovery settings can record worker heartbeats and recover jobs locked by workers that no longer heartbeat.

For more detail, see Worker Lifecycle and Architecture.

Scheduling

Scheduling determines when a job becomes runnable. A job can be available immediately or scheduled for a later time. Graphile Worker RS also exposes cron support through Cron and CronBuilder for recurring work.

Use scheduling when the time a job should run matters more than when it was created, such as sending a reminder later or running a daily report.

For more detail, see Scheduling Model.

Queues and Concurrency

Concurrency controls how many jobs a worker may process at once. Queues add coordination around groups of jobs. They are useful when some work must be serialized or separated from other work.

The database schema includes _private_job_queues, which tracks queue names for serialized job execution. Worker configuration controls the amount of parallel work a process can take on.

For more detail, see Queues and Concurrency.

Database Schema

Graphile Worker RS manages its own PostgreSQL schema and migrations. The default schema name is graphile_worker, and the crate documentation identifies these core tables:

  • _private_jobs stores job data, state, and execution metadata.
  • _private_tasks tracks registered task types.
  • _private_job_queues manages queue names for serialized job execution.
  • _private_workers tracks active worker instances.

For more detail, see Database Schema.

How The Pieces Fit Together

In a typical application:

  1. Define one Rust type per task and implement TaskHandler.
  2. Configure a WorkerOptions value with a PostgreSQL pool and task definitions.
  3. Initialize the worker so migrations and setup can run.
  4. Add jobs from application code or utilities.
  5. Run one or more worker processes to execute runnable jobs.

The important boundary is between tasks and jobs. A task is code compiled into your application. A job is data stored in PostgreSQL that says which task should run, with which payload, and under which execution rules.

Where To Go Next

Start with Architecture for the system-level view, then read Tasks and Payloads and Worker Lifecycle to understand the main programming model. After that, use Scheduling Model, Queues and Concurrency, and Database Schema for the specific behavior you need to configure or operate.