mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
Rootfix usage counter outbox
This commit is contained in:
@@ -6,6 +6,7 @@ use super::route_filters::{
|
||||
};
|
||||
use crate::constants::INTERNAL_GATEWAY_PATH_PREFIXES;
|
||||
use crate::handlers::admin::request::{AdminAppState, AdminRequestContext};
|
||||
use crate::handlers::admin::shared::build_admin_usage_counter_health_payload;
|
||||
use crate::GatewayError;
|
||||
use aether_admin::observability::monitoring::{
|
||||
admin_monitoring_bad_request_response, admin_monitoring_user_behavior_user_id_from_path,
|
||||
@@ -189,6 +190,13 @@ pub(super) async fn build_admin_monitoring_system_status_response(
|
||||
)
|
||||
.unwrap_or(usize::MAX);
|
||||
let tunnel = state.tunnel.stats();
|
||||
let usage_counter_snapshot = state
|
||||
.data
|
||||
.read_usage_counter_health()
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
let usage_counter =
|
||||
build_admin_usage_counter_health_payload(&usage_counter_snapshot, now_unix_secs);
|
||||
|
||||
Ok(build_admin_monitoring_system_status_payload_response(
|
||||
now,
|
||||
@@ -206,5 +214,6 @@ pub(super) async fn build_admin_monitoring_system_status_response(
|
||||
tunnel.active_streams,
|
||||
INTERNAL_GATEWAY_PATH_PREFIXES,
|
||||
recent_errors,
|
||||
usage_counter,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use super::range::{build_comparison_range, parse_bounded_u32};
|
||||
use super::resolve_admin_usage_time_range;
|
||||
use crate::handlers::admin::request::{AdminAppState, AdminRequestContext};
|
||||
use crate::handlers::admin::shared::{query_param_optional_bool, query_param_value};
|
||||
use crate::handlers::admin::shared::{
|
||||
build_admin_usage_counter_health_payload, query_param_optional_bool, query_param_value,
|
||||
};
|
||||
use crate::GatewayError;
|
||||
use aether_admin::observability::stats::{
|
||||
admin_stats_bad_request_response, admin_stats_comparison_empty_response,
|
||||
@@ -21,6 +23,22 @@ use aether_data_contracts::repository::usage::{
|
||||
};
|
||||
use axum::{body::Body, http, response::Response};
|
||||
|
||||
async fn build_usage_counter_health_payload(
|
||||
state: &AdminAppState<'_>,
|
||||
) -> Result<serde_json::Value, GatewayError> {
|
||||
let now_unix_secs = chrono::Utc::now().timestamp().max(0) as u64;
|
||||
let snapshot = state
|
||||
.as_ref()
|
||||
.data
|
||||
.read_usage_counter_health()
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
Ok(build_admin_usage_counter_health_payload(
|
||||
&snapshot,
|
||||
now_unix_secs,
|
||||
))
|
||||
}
|
||||
|
||||
fn usage_summary_to_admin_stats_aggregate(
|
||||
summary: &aether_data_contracts::repository::usage::StoredUsageAuditSummary,
|
||||
) -> AdminStatsAggregate {
|
||||
@@ -211,13 +229,18 @@ pub(super) async fn maybe_build_local_admin_stats_analytics_response(
|
||||
Ok(value) => u64::from(value.unwrap_or(10_000)),
|
||||
Err(detail) => return Ok(Some(admin_stats_bad_request_response(detail))),
|
||||
};
|
||||
let usage_counter = build_usage_counter_health_payload(state).await?;
|
||||
if !state.has_usage_data_reader() {
|
||||
return Ok(Some(admin_stats_provider_performance_empty_response()));
|
||||
return Ok(Some(admin_stats_provider_performance_empty_response(
|
||||
usage_counter,
|
||||
)));
|
||||
}
|
||||
|
||||
let Some((created_from_unix_secs, created_until_unix_secs)) = time_range.to_unix_bounds()
|
||||
else {
|
||||
return Ok(Some(admin_stats_provider_performance_empty_response()));
|
||||
return Ok(Some(admin_stats_provider_performance_empty_response(
|
||||
usage_counter,
|
||||
)));
|
||||
};
|
||||
let performance = state
|
||||
.summarize_usage_provider_performance(&UsageProviderPerformanceQuery {
|
||||
@@ -240,6 +263,7 @@ pub(super) async fn maybe_build_local_admin_stats_analytics_response(
|
||||
.await?;
|
||||
return Ok(Some(build_admin_stats_provider_performance_response(
|
||||
&performance,
|
||||
usage_counter,
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
mod paths;
|
||||
mod payloads;
|
||||
mod proxy_errors;
|
||||
mod usage_counter;
|
||||
|
||||
pub(crate) use self::paths::*;
|
||||
pub(crate) use self::payloads::*;
|
||||
pub(crate) use self::proxy_errors::build_proxy_error_response;
|
||||
pub(crate) use self::usage_counter::build_admin_usage_counter_health_payload;
|
||||
pub(crate) use crate::handlers::shared::{
|
||||
attach_admin_audit_response, build_admin_provider_key_response,
|
||||
decrypt_catalog_secret_with_fallbacks, default_provider_key_status_snapshot,
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
use aether_data_contracts::repository::usage::UsageCounterHealthSnapshot;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
pub(crate) fn build_admin_usage_counter_health_payload(
|
||||
snapshot: &UsageCounterHealthSnapshot,
|
||||
now_unix_secs: u64,
|
||||
) -> Value {
|
||||
let oldest_pending_age_secs = snapshot
|
||||
.oldest_pending_created_at_unix_secs
|
||||
.map(|created_at| now_unix_secs.saturating_sub(created_at));
|
||||
let status = match (snapshot.pending_rows, oldest_pending_age_secs) {
|
||||
(0, _) => "idle",
|
||||
(_, Some(age)) if age >= 60 => "backlogged",
|
||||
_ => "catching_up",
|
||||
};
|
||||
|
||||
json!({
|
||||
"status": status,
|
||||
"outbox_pending_rows": snapshot.pending_rows,
|
||||
"outbox_processed_rows": snapshot.processed_rows,
|
||||
"oldest_pending_created_at_unix_secs": snapshot.oldest_pending_created_at_unix_secs,
|
||||
"oldest_pending_age_secs": oldest_pending_age_secs,
|
||||
"latest_processed_at_unix_secs": snapshot.latest_processed_at_unix_secs,
|
||||
"pending_by_kind": snapshot.pending_by_kind,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use aether_data_contracts::repository::usage::UsageCounterHealthSnapshot;
|
||||
use serde_json::json;
|
||||
|
||||
use super::build_admin_usage_counter_health_payload;
|
||||
|
||||
#[test]
|
||||
fn usage_counter_health_payload_reports_idle_without_pending_rows() {
|
||||
let snapshot = UsageCounterHealthSnapshot {
|
||||
processed_rows: 42,
|
||||
latest_processed_at_unix_secs: Some(1_000),
|
||||
..UsageCounterHealthSnapshot::default()
|
||||
};
|
||||
|
||||
let payload = build_admin_usage_counter_health_payload(&snapshot, 1_100);
|
||||
|
||||
assert_eq!(payload["status"], json!("idle"));
|
||||
assert_eq!(payload["outbox_pending_rows"], json!(0));
|
||||
assert_eq!(payload["outbox_processed_rows"], json!(42));
|
||||
assert_eq!(payload["oldest_pending_age_secs"], json!(null));
|
||||
assert_eq!(payload["latest_processed_at_unix_secs"], json!(1_000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn usage_counter_health_payload_reports_catching_up_for_fresh_backlog() {
|
||||
let mut pending_by_kind = BTreeMap::new();
|
||||
pending_by_kind.insert("api_key".to_string(), 3);
|
||||
let snapshot = UsageCounterHealthSnapshot {
|
||||
pending_rows: 3,
|
||||
oldest_pending_created_at_unix_secs: Some(1_050),
|
||||
pending_by_kind,
|
||||
..UsageCounterHealthSnapshot::default()
|
||||
};
|
||||
|
||||
let payload = build_admin_usage_counter_health_payload(&snapshot, 1_100);
|
||||
|
||||
assert_eq!(payload["status"], json!("catching_up"));
|
||||
assert_eq!(payload["oldest_pending_age_secs"], json!(50));
|
||||
assert_eq!(payload["pending_by_kind"]["api_key"], json!(3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn usage_counter_health_payload_reports_backlogged_for_old_backlog() {
|
||||
let snapshot = UsageCounterHealthSnapshot {
|
||||
pending_rows: 1,
|
||||
oldest_pending_created_at_unix_secs: Some(1_000),
|
||||
..UsageCounterHealthSnapshot::default()
|
||||
};
|
||||
|
||||
let payload = build_admin_usage_counter_health_payload(&snapshot, 1_060);
|
||||
|
||||
assert_eq!(payload["status"], json!("backlogged"));
|
||||
assert_eq!(payload["oldest_pending_age_secs"], json!(60));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::handlers::admin::request::AdminAppState;
|
||||
use crate::handlers::admin::shared::build_admin_usage_counter_health_payload;
|
||||
use crate::handlers::shared::{system_config_bool, system_config_string};
|
||||
use crate::GatewayError;
|
||||
use aether_admin::system::{
|
||||
@@ -114,6 +115,15 @@ pub(crate) async fn build_admin_system_stats_payload(
|
||||
.filter(|provider| provider.is_active)
|
||||
.count() as u64;
|
||||
let stats = state.read_admin_system_stats().await?;
|
||||
let now_unix_secs = chrono::Utc::now().timestamp().max(0) as u64;
|
||||
let usage_counter_snapshot = state
|
||||
.as_ref()
|
||||
.data
|
||||
.read_usage_counter_health()
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
let usage_counter =
|
||||
build_admin_usage_counter_health_payload(&usage_counter_snapshot, now_unix_secs);
|
||||
|
||||
Ok(build_admin_system_stats_payload_pure(
|
||||
stats.total_users,
|
||||
@@ -122,6 +132,7 @@ pub(crate) async fn build_admin_system_stats_payload(
|
||||
active_providers,
|
||||
stats.total_api_keys,
|
||||
stats.total_requests,
|
||||
usage_counter,
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user