use super::{logging, shutdown};
use crate::{app_module, configs::Config};
use std::{future::IntoFuture, sync::Arc};
use tokio::sync::Notify;
pub async fn run() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
crate::configs::load_env()?;
logging::init()?;
let config = Config::from_env()?;
let app = app_module::AppModule::router()?.merge(super::docs::router(
&config,
app_module::AppModule::api_operations(),
)?);
let app = super::router(app, &config);
let listener = tokio::net::TcpListener::bind(config.bind_address).await?;
tracing::info!(address = %listener.local_addr()?, "server listening");
let draining = Arc::new(Notify::new());
let shutdown_started = draining.clone();
let server = axum::serve(
listener,
app.into_make_service_with_connect_info::<std::net::SocketAddr>(),
)
.with_graceful_shutdown(async move {
shutdown::signal().await;
tracing::info!("shutdown requested; draining requests");
shutdown_started.notify_one();
})
.into_future();
tokio::pin!(server);
tokio::select! {
result = &mut server => result?,
_ = draining.notified() => {
match tokio::time::timeout(config.shutdown_grace, &mut server).await {
Ok(result) => result?,
Err(error) => {
tracing::error!("shutdown drain deadline exceeded");
return Err(error.into());
}
}
}
}
tracing::info!("server stopped");
Ok(())
}