From 4aaee59fa4d42b9bd6b84d53975fe448c44c9790 Mon Sep 17 00:00:00 2001 From: ZhenYi <434836402@qq.com> Date: Tue, 21 Apr 2026 23:05:54 +0800 Subject: [PATCH] fix(app): PrometheusHandle must be Data-wrapped before Fn closure capture PrometheusHandle was moved into the HttpServer Fn closure but Fn closures require Clone (not FnOnce). Wrap in web::Data before cloning into the closure. --- apps/app/src/main.rs | 61 ++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/apps/app/src/main.rs b/apps/app/src/main.rs index f7d199e..ebb7add 100644 --- a/apps/app/src/main.rs +++ b/apps/app/src/main.rs @@ -1,19 +1,19 @@ use actix_cors::Cors; use actix_web::cookie::time::Duration; use actix_web::middleware::Logger; -use actix_web::{App, HttpResponse, HttpServer, cookie::Key, web}; +use actix_web::{cookie::Key, web, App, HttpResponse, HttpServer}; use clap::Parser; use db::cache::AppCache; use db::database::AppDatabase; -use sea_orm::ConnectionTrait; -use service::AppService; -use session::SessionMiddleware; -use session::config::{PersistentSession, SessionLifecycle, TtlExtensionPolicy}; -use session::storage::RedisClusterSessionStore; use observability::{ init_tracing_subscriber, install_recorder, prometheus_handler, spawn_http_metrics_poller, - MetricsMiddleware, HttpMetrics, TracingSpanMiddleware, HttpSnapshotGuard, + HttpMetrics, HttpSnapshotGuard, MetricsMiddleware, TracingSpanMiddleware, }; +use sea_orm::ConnectionTrait; +use service::AppService; +use session::config::{PersistentSession, SessionLifecycle, TtlExtensionPolicy}; +use session::storage::RedisClusterSessionStore; +use session::SessionMiddleware; mod args; @@ -57,48 +57,40 @@ async fn main() -> anyhow::Result<()> { let args = ServerArgs::parse(); let service = AppService::new(cfg.clone()).await?; tracing::info!("AppService initialized"); - - // Spawn background task: sync OpenRouter models immediately on startup, - // then every 10 minutes. let _model_sync_handle = service.clone().start_sync_task(); - - // Spawn background task: check workspace billing alerts every 30 minutes. let _billing_alert_handle = service.clone().start_billing_alert_task(); let (shutdown_tx, shutdown_rx) = tokio::sync::broadcast::channel::<()>(1); let worker_service = service.clone(); - let worker_handle = tokio::spawn(async move { - worker_service - .start_room_workers(shutdown_rx) - .await - }); + let worker_handle = + tokio::spawn(async move { worker_service.start_room_workers(shutdown_rx).await }); - // ── Phase 6: OTLP tracing ────────────────────────────────────────────── let _otel_guard = if cfg.otel_enabled().unwrap_or(false) { - let endpoint = cfg.otel_endpoint().unwrap_or_else(|_| "http://localhost:4317".to_string()); - let service_name = cfg.otel_service_name().unwrap_or_else(|_| "app".to_string()); - let service_version = cfg.otel_service_version().unwrap_or_else(|_| "0.1.0".to_string()); + let endpoint = cfg + .otel_endpoint() + .unwrap_or_else(|_| "http://localhost:4317".to_string()); + let service_name = cfg + .otel_service_name() + .unwrap_or_else(|_| "app".to_string()); + let service_version = cfg + .otel_service_version() + .unwrap_or_else(|_| "0.1.0".to_string()); tracing::info!(endpoint = %endpoint, service = %service_name, "OTLP tracing enabled"); - let guard = observability::init_otlp( - &endpoint, - &service_name, - &service_version, - &log_level, - ) - .map_err(|e| anyhow::anyhow!("OTLP init failed: {}", e))?; + let guard = + observability::init_otlp(&endpoint, &service_name, &service_version, &log_level) + .map_err(|e| anyhow::anyhow!("OTLP init failed: {}", e))?; guard } else { None }; - // ── Phase 6: Prometheus metrics ───────────────────────────────────────── - install_recorder(); + let prometheus_handle = install_recorder(); + let prometheus_handle_data = web::Data::new(prometheus_handle); let http_metrics = std::sync::Arc::new(HttpMetrics::new()); - let http_snapshot: HttpSnapshotGuard = - std::sync::Arc::new(std::sync::RwLock::new( - observability::HttpMetricsSnapshot::default(), - )); + let http_snapshot: HttpSnapshotGuard = std::sync::Arc::new(std::sync::RwLock::new( + observability::HttpMetricsSnapshot::default(), + )); let http_snapshot_for_poller = http_snapshot.clone(); spawn_http_metrics_poller( http_metrics.clone(), @@ -147,6 +139,7 @@ async fn main() -> anyhow::Result<()> { .app_data(web::Data::new(db.clone())) .app_data(web::Data::new(cache.clone())) .app_data(http_snapshot_data.clone()) + .app_data(prometheus_handle_data.clone()) .route("/health", web::get().to(health_check)) .route("/metrics", web::get().to(prometheus_handler)) .configure(api::route::init_routes)