Crates.io | async-bb8-diesel |
lib.rs | async-bb8-diesel |
version | 0.2.1 |
source | src |
created_at | 2023-10-17 04:14:40.620728 |
updated_at | 2024-05-15 20:57:51.445493 |
description | async bb8 connection manager for Diesel |
homepage | |
repository | https://github.com/oxidecomputer/async-bb8-diesel |
max_upload_size | |
id | 1005498 |
size | 136,012 |
This crate provides an interface for asynchronously accessing a bb8 connection pool atop Diesel.
This is accomplished by implementing an async version of Diesel's "RunQueryDsl" trait, aptly named "AsyncRunQueryDsl", which operates on an async-compatible connection. When called from an async context, these operations transfer the query to a blocking tokio thread, where it may be executed.
NOTE: This crate pre-dated diesel-async. For new code, consider using that interface directly.
This crate was heavily inspired by both tokio-diesel and bb8-diesel, but serves a slightly different purpose.
Both of those crates rely heavily on the
tokio::block_in_place
function to actually execute synchronous Diesel queries.
Their flow is effectively:
block_in_place
call.block_in_place
.These crates have some advantages by taking this approach:
block_in_place
call.block_in_place
doesn't need to be Send
- it
executes synchronously within the otherwise asynchronous task.However, they also have some downsides:
block_in_place
effectively pauses an async thread for the
duration of the call. This requires a multi-threaded runtime, and reduces
efficacy of one of these threads for the duration of the call.block_in_place
starves all other asynchronous code running in
the same task.This starvation results in some subtle inhibition of other futures, such as in the following example, where a timeout would be ignored if a long-running database operation was issued from the same task as a timeout.
tokio::select! {
// Calls "tokio::block_in_place", doing a synchronous Diesel operation
// on the calling thread...
_ = perform_database_operation() => {},
// ... meaning this asynchronous timeout cannot complete!
_ = sleep_until(timeout) = {},
}
This crate attempts to avoid calls to block_in_place
- which would block the
calling thread - and prefers to use
tokio::spawn_blocking
function. This function moves the requested operation to an entirely distinct
thread where blocking is acceptable, but does not prevent the current task
from executing other asynchronous work.
This isn't entirely free - as this work now needs to be transferred to a new thread, it imposes a "Send + 'static" constraint on the queries which are constructed.