Tokio bridge (id_effect_tokio)

The core id_effect crate defines interpreters (run_blocking, run_async, run_fork, …) and the Runtime trait. Workspace crate id_effect_tokio supplies the Tokio-backed implementation for binaries on #[tokio::main].

Read this section before Platform I/O, HTTP via reqwest, and Axum.

What id_effect_tokio provides

  • TokioRuntime — implements [id_effect::Runtime]: cooperative sleep/yield; forked fibers on Tokio's blocking pool.
  • Re-exportsrun_async, run_blocking, run_fork, yield_now for use at async boundaries.
  • spawn_blocking_run_async — when the effect graph is not Send but must be driven by run_async (Axum uses the same pattern).

Capability DI with Tokio

Build Env manually or via run_with / build_env, then pass it to run_async:

use id_effect::{Env, caps, effect, require, run_async, succeed};
struct ApiToken;

fn fetch() -> Effect<Vec<Quote>, AppError, caps!(ApiToken)> {
    effect!(|r| {
        let token = ~ApiToken;
        // async steps…
        Ok(quotes)
    })
}

#[tokio::main]
async fn main() {
    let mut env = Env::new();
    env.insert::<Cap<ApiToken>>("secret");
    let quotes = run_async(fetch(), env).await?;
}

For provider-based apps, use build_env + run_async:

#![allow(unused)]
fn main() {
let env = build_env([provide!(ConfigLive), provide!(HttpClientLive)])?;
let res = run_async(my_handler(), env).await?;
}

Mental model

ConcernWhere it lives
Describing workEffect<A, E, R>
Capabilitiescaps!(…) + Needs<K> + run_with / build_env
Blocking / testsrun_blocking(effect, env)
Async I/O on Tokioid_effect::run_async(effect, env)

Sharp edges

  1. Send: run_async futures are often not Send — use Axum/Tower adapters or spawn_blocking_run_async.
  2. Router tests: prefer #[tokio::test(flavor = "multi_thread", worker_threads = 2)] when exercising Axum + effects.

Further reading

  • Example: crates/id_effect_tokio/examples/109_tokio_end_to_end.rs
  • cargo doc --open -p id_effect_tokio