elif_http/server/
lifecycle.rs1use crate::{
4 config::HttpConfig,
5 errors::{HttpError, HttpResult},
6 middleware::v2::MiddlewarePipelineV2,
7 routing::ElifRouter,
8 server::health::health_check_handler,
9};
10use elif_core::container::IocContainer;
11use std::net::SocketAddr;
12use std::sync::Arc;
13use tokio::signal;
14use tracing::{info, warn};
15
16pub async fn build_internal_router(
18 container: Arc<IocContainer>,
19 config: HttpConfig,
20 user_router: Option<ElifRouter>,
21 middleware: MiddlewarePipelineV2,
22) -> HttpResult<axum::Router> {
23 let health_container = container.clone();
25 let health_config = config.clone();
26 let health_handler = move |_req: crate::request::ElifRequest| {
27 let container = health_container.clone();
28 let config = health_config.clone();
29 async move {
30 crate::response::ElifResponse::ok()
31 .json(&health_check_handler(container, config).await.0)
32 }
33 };
34
35 let mut router = user_router.unwrap_or_default();
37
38 router = router.get(&config.health_check_path, health_handler);
40
41 router = router.extend_middleware(middleware);
43
44 Ok(router.into_axum_router())
46}
47
48pub async fn start_server(addr: SocketAddr, router: axum::Router) -> HttpResult<()> {
50 let listener = tokio::net::TcpListener::bind(addr)
52 .await
53 .map_err(|e| HttpError::startup(format!("Failed to bind to {}: {}", addr, e)))?;
54
55 info!("✅ Server listening on {}", addr);
56
57 axum::serve(
59 listener,
60 router.into_make_service_with_connect_info::<SocketAddr>(),
61 )
62 .with_graceful_shutdown(shutdown_signal())
63 .await
64 .map_err(|e| HttpError::internal(format!("Server error: {}", e)))?;
65
66 Ok(())
67}
68
69async fn shutdown_signal() {
71 let ctrl_c = async {
72 signal::ctrl_c()
73 .await
74 .expect("Failed to install Ctrl+C handler");
75 };
76
77 #[cfg(unix)]
78 let terminate = async {
79 signal::unix::signal(signal::unix::SignalKind::terminate())
80 .expect("Failed to install signal handler")
81 .recv()
82 .await;
83 };
84
85 #[cfg(not(unix))]
86 let terminate = std::future::pending::<()>();
87
88 tokio::select! {
89 _ = ctrl_c => {
90 warn!("📡 Received Ctrl+C, shutting down gracefully...");
91 },
92 _ = terminate => {
93 warn!("📡 Received terminate signal, shutting down gracefully...");
94 },
95 }
96}