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

Runtime, TLS, and Drivers

Graphile Worker RS exposes three separate feature choices for database access:

  • an async runtime feature
  • a TLS backend feature
  • a PostgreSQL driver feature

The default crate features enable the common path:

[dependencies]
graphile_worker = "0.13"

This is equivalent to enabling runtime-tokio, tls-rustls, and driver-sqlx.

Feature Groups

Runtime features choose the async runtime used by the worker internals:

FeatureNotes
runtime-tokioDefault runtime. Required by driver-tokio-postgres.
runtime-async-stdSupported with the SQLx driver.

TLS features choose the TLS implementation passed through to the database crates:

FeatureNotes
tls-rustlsDefault TLS backend for SQLx and tokio-postgres.
tls-native-tlsNative TLS backend for SQLx and tokio-postgres.

When both TLS features are enabled, native TLS takes precedence. The tokio-postgres driver uses public certificate roots with rustls and the system root store with native TLS. Set PGSSLROOTCERT to a PEM file to add a private root certificate for either backend. An unset, empty, or system value keeps the selected backend's default roots; system does not change sslmode or switch Rustls to the platform root store. Use sslmode=require in the connection URL when the connection must be encrypted.

Driver features choose which PostgreSQL client integration is compiled:

FeatureNotes
driver-sqlxDefault driver. Enables the optional sqlx dependency.
driver-tokio-postgresEnables the tokio-postgres based driver path and also enables runtime-tokio.

Valid Combinations

Use one runtime, one TLS backend when your driver needs TLS, and one driver. The combinations exercised by the repository test matrix are:

RuntimeDriverTLS in tested commandStatus
runtime-tokiodriver-sqlxtls-rustlsDefault tested path.
runtime-async-stddriver-sqlxtls-rustlsTested SQLx async-std path.
runtime-tokiodriver-tokio-postgresNot added by the matrix commandTested plaintext tokio-postgres path.
runtime-tokiodriver-tokio-postgrestls-rustls and tls-native-tlsTested against TLS-only PostgreSQL.

driver-tokio-postgres is Tokio-only. The repository runtime test command rejects driver-tokio-postgres with any runtime other than runtime-tokio.

Cargo Examples

Use defaults unless you have a reason to choose another runtime or driver:

[dependencies]
graphile_worker = "0.13"

To make the default feature set explicit:

[dependencies]
graphile_worker = { version = "0.13", default-features = false, features = [
  "runtime-tokio",
  "tls-rustls",
  "driver-sqlx",
] }

To use SQLx with async-std:

[dependencies]
graphile_worker = { version = "0.13", default-features = false, features = [
  "runtime-async-std",
  "tls-rustls",
  "driver-sqlx",
] }

To use the tokio-postgres driver:

[dependencies]
graphile_worker = { version = "0.13", default-features = false, features = [
  "driver-tokio-postgres",
  "tls-rustls",
] }

driver-tokio-postgres enables runtime-tokio for Graphile Worker RS. The selected TLS backend is used for both pooled queries and the LISTEN connection, including listener reconnections. The TokioPostgresDatabase::new(pool) path cannot configure the separate LISTEN connection and continues to use polling.

WorkerUtils With A Caller-Owned Executor

WorkerUtils::with_executor keeps the high-level scheduling and job-management API while routing its database operations through a supported executor. This is the preferred API when a job must be committed atomically with application data.

let mut tx = pool.begin().await?;

save_order(&mut tx, &order).await?;

{
    let mut utils = worker.create_utils().with_executor(&mut tx);
    utils.add_job(SendOrderConfirmation { order_id: order.id }, JobSpec::default()).await?;
}

tx.commit().await?;

The facade borrows the executor but never commits or rolls it back. Drop the facade, or consume it with into_inner, before completing the transaction. It supports both SQLx and tokio-postgres executor types through DbExecutorArg.

Maintenance operations that own their transaction or mutate shared maintenance state are intentionally not exposed by the facade: cleanup, migrate, and the stale-worker sweep methods.

SQLx Driver Executor Arguments

With driver-sqlx, the SQL helpers accept SQLx executors used by the tests:

  • a pool
  • an acquired connection
  • a transaction

That means direct SQL helpers can participate in a caller-owned transaction. In the tested path, a job added inside a SQLx transaction disappears after the caller rolls the transaction back.

use graphile_worker::sql::add_job::single::add_job;
use graphile_worker::{JobSpec, Schema};
use serde_json::json;

let mut tx = pool.begin().await?;

add_job(
    &mut tx,
    &Schema::default(),
    "send_email",
    json!({ "user_id": 42 }),
    JobSpec::default(),
    false,
)
.await?;

tx.commit().await?;

The lower-level DbExecutorArg path is also tested for execute, fetch_all, and fetch_one with SQLx pool, connection, and transaction executors.

tokio-postgres Driver Executor Arguments

With driver-tokio-postgres, the SQL helpers accept tokio-postgres and deadpool-postgres executor arguments used by the tests:

  • tokio_postgres::Client
  • tokio_postgres::Transaction
  • deadpool_postgres::Pool
  • a deadpool_postgres client checked out from the pool
use graphile_worker::sql::add_job::single::add_job;
use graphile_worker::{JobSpec, Schema};
use serde_json::json;
use tokio_postgres::NoTls;

let (client, connection) =
    tokio_postgres::connect("postgres://postgres:postgres@localhost/postgres", NoTls).await?;

tokio::spawn(async move {
    let _ = connection.await;
});

add_job(
    &client,
    &Schema::default(),
    "send_email",
    json!({ "user_id": 42 }),
    JobSpec::default(),
    false,
)
.await?;

The tested tokio-postgres path also verifies that jobs added through a tokio-postgres transaction participate in the caller transaction and are not persisted after rollback.

Running the Matrix Locally

The project justfile defines targeted runtime and driver checks. If DATABASE_URL is not set, the runtime target delegates to the Docker-backed variant.

just test-runtime runtime-tokio driver-sqlx
just test-runtime runtime-async-std driver-sqlx
just test-runtime runtime-tokio driver-tokio-postgres

The combined Docker matrix runs the same supported combinations against a local PostgreSQL container:

just test-docker-all-matrices

Proxies Without Persistent Prepared Statements

SQLx uses persistent named statements by default. For a proxy that cannot preserve them, configure the database wrapper before using a fresh pool:

let database = graphile_worker::sqlx::SqlxDatabase::new(pool)
    .with_prepared_statements(false);
let worker = graphile_worker::WorkerOptions::default()
    .database(database)
    // Register task handlers here.
    .init()
    .await?;

This setting also applies to transactions opened through Database::begin. Raw SQLx pool/connection/transaction executors retain their normal SQLx behavior. SQLx may reuse statements already cached on an existing pool; use a fresh pool (and set its statement cache capacity to zero if other application code shares it). The tokio-postgres driver already issues unnamed statements. This controls server-side statements independently of the worker's SQL-text cache.