//! Timing metrics for crawler operations (see `crawl_metrics` table, 0028). //! //! One [`OpRow`] per completed operation (manga list walk, manga detail, //! cover, whole chapter); [`OpSummary`] is the per-type average roll-up that //! drives the admin Metrics tab. Per-page crawl timing is derived on the //! client from the `chapter` summary's `avg_items` (pages/chapter), not //! stored per image. Analysis duration lives on `page_analysis`, not here. use chrono::{DateTime, Utc}; use serde::Serialize; use sqlx::FromRow; use uuid::Uuid; /// One time bucket of a metrics series — count, ok/failed split, and mean /// duration over the bucket. Shared by the crawl-ops and analysis trend /// charts (both are `{t, n, ok, failed, avg_ms}` over a `date_trunc` window). /// Empty intervals are simply absent; the client fills the continuous axis. #[derive(Debug, Clone, Serialize, FromRow)] pub struct MetricsBucket { /// Bucket start (`date_trunc(unit, finished_at|analyzed_at)`). pub t: DateTime, pub n: i64, pub ok: i64, pub failed: i64, pub avg_ms: Option, } /// Per-operation-type average roll-up over a time window. #[derive(Debug, Clone, Serialize, FromRow)] pub struct OpSummary { /// `manga_list` | `manga_detail` | `manga_cover` | `chapter`. pub op: String, /// Mean duration in milliseconds (`NULL`→absent only when `n = 0`). pub avg_ms: Option, /// Total operations in the window. pub n: i64, pub ok: i64, pub failed: i64, /// Mean `items` (pages/chapter, mangas/list-walk); `None` when unused. pub avg_items: Option, } /// One timed operation, resolved to manga/chapter labels for the recent-ops log. #[derive(Debug, Clone, Serialize, FromRow)] pub struct OpRow { pub id: Uuid, pub op: String, pub manga_id: Option, pub manga_title: Option, pub chapter_id: Option, pub chapter_number: Option, pub outcome: String, pub duration_ms: i64, pub items: Option, pub error: Option, pub finished_at: DateTime, }