Skip to main content

Crate runtime_bridge

Crate runtime_bridge 

Source
Expand description

Sync→async runtime bridge for Heddle.

RuntimeBridge is a worker thread that owns a private current-thread Tokio runtime. Synchronous code hands futures to the worker over an async mpsc channel; the worker tokio::spawns each future on its own runtime and the caller blocks on a per-request reply channel until the task completes. The caller’s runtime (if any) is never re-entered.

§Why

Heddle has several ObjectStore / OpLogBackend / RefBackend implementations whose trait surface is synchronous but whose underlying I/O is async (aws-sdk-s3, sqlx, etc.). A naive bridge — Handle::current().block_on(...) or tokio::task::block_in_place(|| Handle::current().block_on(...)) — breaks in caller-flavor-dependent ways:

  • Handle::current().block_on(...) panics with “Cannot start a runtime from within a runtime” when the caller is already on a Tokio runtime.
  • block_in_place(...) panics with “can call blocking only when running on the multi-threaded runtime” when the caller is on a current-thread runtime (e.g. #[tokio::test(flavor = "current_thread")]).
  • Neither works at all when the caller is on a non-Tokio thread.

Routing through this bridge sidesteps all three: the future runs on the bridge’s private runtime regardless of who calls it, and the caller’s thread simply blocks on a reply channel.

§Concurrency

The worker dispatches each request via tokio::spawn rather than awaiting it inline, so concurrent callers sharing one bridge can progress in parallel on the worker’s runtime. This preserves the connection-level parallelism of pools like sqlx::PgPool instead of head-of-line blocking every caller behind the slowest in-flight query.

§Error recovery

RuntimeBridge::block_on returns Result<T, BridgeError> so a dead worker surfaces as a recoverable error in the caller’s Result-typed API rather than escalating into a process-level panic. A bridged task that panics aborts only that task: its reply channel is dropped and the waiting caller observes BridgeError::ResponseLost; the worker keeps serving other requests.

§Shutdown

Dropping the bridge drops the Sender; the worker’s Receiver::recv then returns None, the loop breaks, and the runtime is dropped on the worker thread. The JoinHandle is retained on the bridge so the thread isn’t reaped before its in-flight requests drain.

Structs§

RuntimeBridge
Worker thread + private current-thread Tokio runtime used to drive async work off the caller’s runtime.

Enums§

BridgeError
Errors returned by RuntimeBridge::block_on when the bridge cannot complete a request. Both variants signal an unrecoverable problem with the worker for this one call; the bridge as a whole remains usable for subsequent calls only when BridgeError::ResponseLost is returned (the worker is still alive, just this one task died).