#![expect(
clippy::unwrap_used,
clippy::expect_used,
reason = "example/test/bench: panic-on-error and print-for-output are the standard patterns for demos and harnesses"
)]
use rama::{
Layer,
extensions::Extensions,
http::{
StatusCode,
headers::exotic::XClacksOverhead,
layer::{
error_handling::ErrorHandlerLayer, set_header::SetResponseHeaderLayer,
trace::TraceLayer,
},
server::HttpServer,
service::web::Router,
},
layer::{AbortableLayer, abort::AbortController},
rt::Executor,
tcp::server::TcpListener,
telemetry::tracing::{
self,
level_filters::LevelFilter,
subscriber::{EnvFilter, fmt, layer::SubscriberExt, util::SubscriberInitExt},
},
};
use std::{sync::Arc, time::Duration};
const ADDRESS: &str = "127.0.0.1:62047";
#[tokio::main]
async fn main() {
tracing::subscriber::registry()
.with(fmt::layer())
.with(
EnvFilter::builder()
.with_default_directive(LevelFilter::DEBUG.into())
.from_env_lossy(),
)
.init();
let graceful = rama::graceful::Shutdown::default();
let router =
Router::new()
.with_get("/", StatusCode::OK)
.with_get("/abort", async |ext: Extensions| {
ext.get_ref::<AbortController>().unwrap().abort().await;
StatusCode::INTERNAL_SERVER_ERROR
});
let http_middlewares = (
TraceLayer::new_for_http(),
SetResponseHeaderLayer::<XClacksOverhead>::if_not_present_default_typed(),
ErrorHandlerLayer::new(),
);
let tcp_svc = AbortableLayer::new().into_layer(
HttpServer::auto(Executor::graceful(graceful.guard()))
.service(Arc::new(http_middlewares.into_layer(router))),
);
graceful.spawn_task_fn(async |guard| {
tracing::info!("running service at: {ADDRESS}");
let exec = Executor::graceful(guard);
TcpListener::bind_address(ADDRESS, exec)
.await
.unwrap()
.serve(tcp_svc)
.await;
});
graceful
.shutdown_with_limit(Duration::from_secs(30))
.await
.expect("graceful shutdown");
}