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§
- Client
Config - configuration for the tcp Connector
- Listener
Config - An advanced listener builder.
- Runtime
- A type-erased
RuntimeTraitimplementation. Think of this as anArc<dyn RuntimeTrait> - Smol
Runtime - Runtime for Smol
- Smol
Transport - A transport newtype for smol
- Smol
UdpSocket - 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
- Into
Listen Addr - Conversion into a single TCP bind address.
- Runtime
Trait - A trait that covers async runtime behavior.