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

Quick Start

This page shows the smallest useful Graphile Worker RS setup: define one typed task, register it with a worker, add a job, and start processing jobs.

Add Dependencies

Graphile Worker RS runs against PostgreSQL. With the default Tokio runtime, rustls TLS, and SQLx driver, a minimal application can connect with a database URL and these dependencies:

[dependencies]
graphile_worker = "0.13"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde = { version = "1", features = ["derive"] }

Define a Typed Task

A task is a Rust type that can be serialized into the job payload and deserialized when the worker runs it. Implement TaskHandler for the payload type and give it a stable identifier.

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

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

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

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

The identifier is the task name stored in PostgreSQL. Jobs with this identifier will be decoded as SendEmail and passed to SendEmail::run.

Create and Run a Worker

Configure a PostgreSQL connection string, register the task with define_job, initialize the worker, and call run.

use graphile_worker::WorkerOptions;

async fn run_worker() -> Result<(), Box<dyn std::error::Error>> {
    let worker = WorkerOptions::default()
        .database_url("postgres://postgres:password@localhost/mydb")
        .concurrency(5)
        .schema("graphile_worker")
        .define_job::<SendEmail>()
        .init()
        .await?;

    worker.run().await?;

    Ok(())
}

init connects to PostgreSQL, runs the worker migrations for the configured schema, registers the task handlers, and returns a Worker. The schema defaults to graphile_worker if you do not set one.

Add a Job

After initialization, use create_utils to get WorkerUtils. Its add_job method accepts the typed task payload and a JobSpec.

use graphile_worker::JobSpecBuilder;

let helpers = worker.create_utils();

helpers
    .add_job(
        SendEmail {
            to: "ada@example.com".to_string(),
            subject: "Welcome".to_string(),
            body: "Thanks for signing up.".to_string(),
        },
        JobSpecBuilder::new().build(),
    )
    .await?;

For scheduled jobs, set run_at on the job spec before building it. This example uses chrono; add it to your application if you schedule from Rust timestamps:

use chrono::{Duration, offset::Utc};
use graphile_worker::JobSpecBuilder;

helpers
    .add_job(
        SendEmail {
            to: "ada@example.com".to_string(),
            subject: "Welcome".to_string(),
            body: "Thanks for signing up.".to_string(),
        },
        JobSpecBuilder::new()
            .run_at(Utc::now() + Duration::seconds(10))
            .build(),
    )
    .await?;

Complete Shape

This combines the pieces into one application shape. In a real application you can add jobs from request handlers, services, or startup code while one or more workers process them.

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

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

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

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

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let worker = WorkerOptions::default()
        .database_url("postgres://postgres:password@localhost/mydb")
        .concurrency(5)
        .schema("graphile_worker")
        .define_job::<SendEmail>()
        .init()
        .await?;

    worker
        .create_utils()
        .add_job(
            SendEmail {
                to: "ada@example.com".to_string(),
                subject: "Welcome".to_string(),
                body: "Thanks for signing up.".to_string(),
            },
            JobSpecBuilder::new().build(),
        )
        .await?;

    worker.run().await?;

    Ok(())
}

For a runnable example in the repository, see examples/simple.rs. For more configuration options, continue with Configuration.