# 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:
```toml
[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:
| `runtime-tokio` | Default runtime. Required by `driver-tokio-postgres`. |
| `runtime-async-std` | Supported with the SQLx driver. |
TLS features choose the TLS implementation passed through to the database
crates:
| `tls-rustls` | Default TLS backend for SQLx and tokio-postgres. |
| `tls-native-tls` | Native 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:
| `driver-sqlx` | Default driver. Enables the optional `sqlx` dependency. |
| `driver-tokio-postgres` | Enables 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:
| `runtime-tokio` | `driver-sqlx` | `tls-rustls` | Default tested path. |
| `runtime-async-std` | `driver-sqlx` | `tls-rustls` | Tested SQLx async-std path. |
| `runtime-tokio` | `driver-tokio-postgres` | Not added by the matrix command | Tested plaintext tokio-postgres path. |
| `runtime-tokio` | `driver-tokio-postgres` | `tls-rustls` and `tls-native-tls` | Tested 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:
```toml
[dependencies]
graphile_worker = "0.13"
```
To make the default feature set explicit:
```toml
[dependencies]
graphile_worker = { version = "0.13", default-features = false, features = [
"runtime-tokio",
"tls-rustls",
"driver-sqlx",
] }
```
To use SQLx with async-std:
```toml
[dependencies]
graphile_worker = { version = "0.13", default-features = false, features = [
"runtime-async-std",
"tls-rustls",
"driver-sqlx",
] }
```
To use the tokio-postgres driver:
```toml
[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.
```rust,ignore
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.
```rust,ignore
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
```rust,ignore
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.
```bash
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:
```bash
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:
```rust,ignore
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.