Skip to main content

Crate trillium_smol

Crate trillium_smol 

Source
Expand description

§Trillium adapter using smol and async-global-executor

§Default / 12-factor applications

trillium_smol::run(|conn: trillium::Conn| async move { conn.ok("hello smol") });

§Server configuration

For more details, see trillium_smol::config.

let swansong = trillium_smol::Swansong::new();
trillium_smol::config()
    .with_port(0)
    .with_host("127.0.0.1")
    .without_signals()
    .with_nodelay()
    .with_acceptor(()) // see [`trillium_rustls`], [`trillium_native_tls`], and [`trillium_openssl`]
    .with_swansong(swansong)
    .run(|conn: trillium::Conn| async move { conn.ok("hello smol") });

For advanced binding — several listeners on one server, fallible binds you can recover from, or adopting an already-bound socket — call .listeners() to get a ListenerConfig.

§Thread-per-core with SO_REUSEPORT on Linux

SO_REUSEPORT is a socket option that lets several sockets bind the same address and port at once, with the kernel distributing incoming connections across them. Enable the reuseport cargo feature on Linux to use it for thread-per-core fan-out:

use trillium::Conn;

fn main() -> std::io::Result<()> {
    trillium_smol::config()
        .listeners()
        .bind_reuseport_tcp(8080)?
        .run(|conn: Conn| async move { conn.ok("hello") });
    Ok(())
}

Each worker thread runs its own single-threaded executor, pinned to a core, driving that worker’s accept loop — one SO_REUSEPORT listener per worker, and every connection it accepts is handled on that same executor. The shared multi-threaded global executor is still present alongside them, hosting HTTP/3, signal handling, and the application tasks you spawn, so QUIC is never fanned out this way. Set the worker count with .with_reuseport_workers(n); it defaults to the WORKERS environment variable, or if that’s not set, to available parallelism.

This trades the global executor’s load balancing for per-core locality, which can improve throughput for short, CPU-cheap requests served over many connections. It is gated off on platforms where plain SO_REUSEPORT does not distribute connections (including macOS), where it would offer no benefit.

§Client

trillium_testing::with_server("ok", |url| async move {
    use trillium_client::{Client, Conn};
    use trillium_smol::TcpConnector;
    let mut conn = Conn::<TcpConnector>::get(url.clone()).execute().await?;
    assert_eq!(conn.response_body().read_string().await?, "ok");

    let client = Client::<TcpConnector>::new();
    let mut conn = client.get(url);
    conn.send().await?;
    assert_eq!(conn.response_body().read_string().await?, "ok");
    Ok(())
});

Re-exports§

pub use async_global_executor;
pub use async_io;
pub use async_net;

Structs§

ClientConfig
configuration for the tcp Connector
ListenerConfig
An advanced listener builder.
Runtime
A type-erased RuntimeTrait implementation. Think of this as an Arc<dyn RuntimeTrait>
SmolRuntime
Runtime for Smol
SmolTransport
A transport newtype for smol
SmolUdpSocket
Async-io-backed UDP socket for use with QUIC transports.
Swansong
🦢 Shutdown manager

Enums§

Binding
A wrapper enum that has blanket implementations for common traits like TryFrom, Stream, AsyncRead, and AsyncWrite. This can contain listeners (like TcpListener), Streams (like Incoming), or bytestreams (like TcpStream).

Traits§

Connector
Interface for runtime and tls adapters for the trillium client
IntoListenAddr
Conversion into a single TCP bind address.
RuntimeTrait
A trait that covers async runtime behavior.

Functions§

config
Configures a server before running it
run
Runs a trillium handler in a sync context with default config
run_async
Runs a trillium handler in an async context with default config