|
| 1 | +use std::{net::SocketAddr, sync::Arc, time::Duration}; |
| 2 | + |
| 3 | +use anyhow::Result; |
1 | 4 | use axum::{routing::get, Router}; |
2 | | -use std::{net::SocketAddr, sync::Arc}; |
3 | | -use tokio::net::TcpListener; |
| 5 | +use status_bridge::{ |
| 6 | + bridge_monitoring_task, get_bridge_status, run_withdrawal_indexer, BridgeMonitoringContext, |
| 7 | +}; |
| 8 | +use status_config::Config; |
| 9 | +use status_network::{fetch_statuses_task, get_network_status, NetworkMonitoringContext}; |
| 10 | +use strata_tasks::TaskManager; |
| 11 | +use tokio::{net::TcpListener, runtime}; |
4 | 12 | use tower_http::cors::{Any, CorsLayer}; |
5 | 13 | use tracing::info; |
6 | 14 |
|
7 | | -use status_bridge::{bridge_monitoring_task, get_bridge_status, BridgeMonitoringContext}; |
8 | | -use status_config::Config; |
9 | | -use status_network::{fetch_statuses_task, get_network_status, NetworkMonitoringContext}; |
| 15 | +const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5); |
10 | 16 |
|
11 | | -#[tokio::main] |
12 | | -async fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 17 | +fn main() -> Result<()> { |
13 | 18 | tracing_subscriber::fmt::fmt() |
14 | 19 | .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) |
15 | 20 | .init(); |
16 | 21 |
|
17 | | - // Load configuration from TOML |
| 22 | + let runtime = runtime::Builder::new_multi_thread() |
| 23 | + .enable_all() |
| 24 | + .thread_name("status-dashboard-rt") |
| 25 | + .build()?; |
| 26 | + |
18 | 27 | let config_path = std::env::var("CONFIG_PATH").unwrap_or_else(|_| "config.toml".to_string()); |
19 | 28 | let config = Arc::new(Config::load_from_path(&config_path)); |
20 | 29 |
|
21 | | - let cors = CorsLayer::new().allow_origin(Any); |
| 30 | + let task_manager = TaskManager::new(runtime.handle().clone()); |
| 31 | + let executor = task_manager.create_executor(); |
22 | 32 |
|
23 | 33 | let network_context = Arc::new(NetworkMonitoringContext::new(config.network().clone())); |
24 | | - let network_context_clone = Arc::clone(&network_context); |
25 | | - |
26 | | - tokio::spawn(async move { |
27 | | - fetch_statuses_task(network_context_clone).await; |
28 | | - }); |
29 | | - |
30 | | - // Bridge monitoring |
31 | 34 | let bridge_context = Arc::new(BridgeMonitoringContext::new(config.bridge().clone())); |
32 | | - let bridge_context_clone = Arc::clone(&bridge_context); |
33 | | - |
34 | | - tokio::spawn(async move { |
35 | | - bridge_monitoring_task(bridge_context_clone).await; |
36 | | - }); |
37 | 35 |
|
| 36 | + let cors = CorsLayer::new().allow_origin(Any); |
38 | 37 | let app = Router::new() |
39 | 38 | .route( |
40 | 39 | "/api/status", |
41 | | - get(move || get_network_status(network_context)), |
| 40 | + get({ |
| 41 | + let network_context = Arc::clone(&network_context); |
| 42 | + move || get_network_status(Arc::clone(&network_context)) |
| 43 | + }), |
42 | 44 | ) |
43 | 45 | .route( |
44 | 46 | "/api/bridge_status", |
45 | | - get(move || get_bridge_status(bridge_context)), |
| 47 | + get({ |
| 48 | + let bridge_context = Arc::clone(&bridge_context); |
| 49 | + move || get_bridge_status(Arc::clone(&bridge_context)) |
| 50 | + }), |
46 | 51 | ) |
47 | 52 | .layer(cors); |
48 | 53 |
|
49 | 54 | let addr = SocketAddr::from(( |
50 | 55 | config.server().host().parse::<std::net::IpAddr>()?, |
51 | 56 | config.server().port(), |
52 | 57 | )); |
53 | | - info!(%addr, "Server running at http://{}", addr); |
54 | 58 |
|
55 | | - let listener = TcpListener::bind(addr).await?; |
56 | | - axum::serve(listener, app).await?; |
| 59 | + executor.spawn_critical_async_with_shutdown("network-monitoring", { |
| 60 | + let network_context = Arc::clone(&network_context); |
| 61 | + move |shutdown| async move { fetch_statuses_task(network_context, shutdown).await } |
| 62 | + }); |
| 63 | + |
| 64 | + executor.spawn_critical_async_with_shutdown("bridge-monitoring", { |
| 65 | + let bridge_context = Arc::clone(&bridge_context); |
| 66 | + move |shutdown| async move { bridge_monitoring_task(bridge_context, shutdown).await } |
| 67 | + }); |
| 68 | + |
| 69 | + executor.spawn_critical_async_with_shutdown("withdrawal-indexer", { |
| 70 | + let datadir = config.datadir().to_path_buf(); |
| 71 | + let cfg = config.withdrawal_indexer().clone(); |
| 72 | + move |shutdown| async move { run_withdrawal_indexer(&datadir, cfg, shutdown).await } |
| 73 | + }); |
| 74 | + |
| 75 | + executor.spawn_critical_async_with_shutdown("http-server", { |
| 76 | + move |shutdown| async move { |
| 77 | + let listener = TcpListener::bind(addr).await?; |
| 78 | + info!(%addr, "Server running at http://{}", addr); |
| 79 | + let shutdown_future = async move { |
| 80 | + shutdown.wait_for_shutdown().await; |
| 81 | + }; |
| 82 | + |
| 83 | + axum::serve(listener, app) |
| 84 | + .with_graceful_shutdown(shutdown_future) |
| 85 | + .await?; |
| 86 | + |
| 87 | + Ok(()) |
| 88 | + } |
| 89 | + }); |
| 90 | + |
| 91 | + task_manager.start_signal_listeners(); |
| 92 | + task_manager.monitor(Some(SHUTDOWN_TIMEOUT))?; |
57 | 93 |
|
| 94 | + info!("Exiting status dashboard backend"); |
58 | 95 | Ok(()) |
59 | 96 | } |
0 commit comments