Expand description
Diesel adapter — sync core fully isolated behind spawn_blocking.
§The blocking rule
Classic Diesel (and its r2d2 pool) is synchronous: pool.get() can
park a thread and queries block until complete. Neither may ever run on
a tokio worker. This adapter ships the whole job — pool acquisition,
queries, and the transaction — to the blocking thread pool as one
closure, so HTTP workers are never starved:
let users = diesel_pool.run(|conn| {
users::table.limit(10).load::<User>(conn)
}).await?;
// Whole transaction in one closure — commit on Ok, rollback on Err:
diesel_pool.transaction(|conn| {
diesel::insert_into(notes::table).values(&new_note).execute(conn)?;
diesel::insert_into(outbox::table).values(&event).execute(conn)
}).await?;Because a sync transaction cannot be held across .await,
#[Transactional] deliberately rejects Diesel pools (see data::tx) —
DieselBlockingPool::transaction is the supported equivalent, with the
same commit-on-Ok / rollback-on-Err contract enforced by Diesel itself.
§Sizing invariant
Keep r2d2 pool size ≤ tokio’s blocking-thread budget (default 512);
otherwise jobs queue behind thread availability instead of pool
availability and the backpressure signal lands in the wrong place.
Structs§
- Diesel
Blocking Pool - Cloneable (Arc-backed) handle around a Diesel
r2d2pool.