chore: add loadtest observability setup

This commit is contained in:
kdletters
2026-05-16 22:44:30 +08:00
parent 7f16e88e57
commit 0305b79440
55 changed files with 2867 additions and 1622 deletions

View File

@@ -3,6 +3,7 @@
pub mod module_bindings;
mod mapper;
mod telemetry;
use mapper::*;
pub use mapper::{
AiResultReferenceRecord, AiTaskMutationRecord, AiTaskRecord, AiTaskStageRecord,
@@ -142,6 +143,24 @@ use module_npc::{
NpcStanceProfile as DomainNpcStanceProfile, NpcStateSnapshot as DomainNpcStateSnapshot,
ResolveNpcInteractionInput as DomainResolveNpcInteractionInput,
};
use module_puzzle::{
PuzzleAgentMessageSnapshot as DomainPuzzleAgentMessageSnapshot,
PuzzleAgentSessionSnapshot as DomainPuzzleAgentSessionSnapshot,
PuzzleAgentSuggestedAction as DomainPuzzleAgentSuggestedAction,
PuzzleAnchorItem as DomainPuzzleAnchorItem, PuzzleAnchorPack as DomainPuzzleAnchorPack,
PuzzleBoardSnapshot as DomainPuzzleBoardSnapshot,
PuzzleCellPosition as DomainPuzzleCellPosition,
PuzzleCreatorIntent as DomainPuzzleCreatorIntent, PuzzleDraftLevel as DomainPuzzleDraftLevel,
PuzzleGeneratedImageCandidate as DomainPuzzleGeneratedImageCandidate,
PuzzleMergedGroupState as DomainPuzzleMergedGroupState,
PuzzlePieceState as DomainPuzzlePieceState, PuzzleResultDraft as DomainPuzzleResultDraft,
PuzzleResultPreviewBlocker as DomainPuzzleResultPreviewBlocker,
PuzzleResultPreviewEnvelope as DomainPuzzleResultPreviewEnvelope,
PuzzleResultPreviewFinding as DomainPuzzleResultPreviewFinding,
PuzzleRunSnapshot as DomainPuzzleRunSnapshot,
PuzzleRuntimeLevelSnapshot as DomainPuzzleRuntimeLevelSnapshot,
PuzzleWorkProfile as DomainPuzzleWorkProfile,
};
use module_runtime::{
AnalyticsMetricQueryResponse as DomainAnalyticsMetricQueryResponse, RuntimeBrowseHistoryRecord,
RuntimePlatformTheme as DomainRuntimePlatformTheme, RuntimeProfileDashboardRecord,
@@ -307,56 +326,72 @@ impl SpacetimeClient {
async fn call_after_connect<T>(
&self,
procedure: &'static str,
call: impl FnOnce(&DbConnection, ProcedureResultSender<T>) + Send + 'static,
) -> Result<T, SpacetimeClientError>
where
T: Send + 'static,
{
let metrics_guard = telemetry::begin_procedure(procedure);
let (sender, receiver) = oneshot::channel();
let result_sender = Arc::new(Mutex::new(Some(sender)));
let lease = self.acquire_connection().await?;
let final_result = if let Some(connection) = lease.connection.as_ref() {
call(&connection.connection, result_sender.clone());
match timeout(self.config.procedure_timeout, receiver).await {
Ok(inner) => match inner {
Ok(value) => value,
Err(_) => Err(SpacetimeClientError::ConnectDropped),
},
Err(_) => Err(Self::resolve_timeout_error(Some(connection))),
let final_result = match self.acquire_connection().await {
Ok(lease) => {
let result = if let Some(connection) = lease.connection.as_ref() {
call(&connection.connection, result_sender.clone());
match timeout(self.config.procedure_timeout, receiver).await {
Ok(inner) => match inner {
Ok(value) => value,
Err(_) => Err(SpacetimeClientError::ConnectDropped),
},
Err(_) => Err(Self::resolve_timeout_error(Some(connection))),
}
} else {
Err(SpacetimeClientError::Runtime(
"SpacetimeDB 连接租约缺少连接".to_string(),
))
};
self.release_connection(lease).await;
result
}
} else {
Err(SpacetimeClientError::Runtime(
"SpacetimeDB 连接租约缺少连接".to_string(),
))
Err(error) => Err(error),
};
self.release_connection(lease).await;
metrics_guard.finish(&final_result);
final_result
}
async fn call_reducer_after_connect(
&self,
procedure: &'static str,
call: impl FnOnce(&DbConnection, ReducerResultSender) + Send + 'static,
) -> Result<(), SpacetimeClientError> {
let metrics_guard = telemetry::begin_procedure(procedure);
let (sender, receiver) = oneshot::channel();
let result_sender = Arc::new(Mutex::new(Some(sender)));
let lease = self.acquire_connection().await?;
let final_result = if let Some(connection) = lease.connection.as_ref() {
call(&connection.connection, result_sender.clone());
match timeout(self.config.procedure_timeout, receiver).await {
Ok(inner) => match inner {
Ok(value) => value,
Err(_) => Err(SpacetimeClientError::ConnectDropped),
},
Err(_) => Err(Self::resolve_timeout_error(Some(connection))),
let final_result = match self.acquire_connection().await {
Ok(lease) => {
let result = if let Some(connection) = lease.connection.as_ref() {
call(&connection.connection, result_sender.clone());
match timeout(self.config.procedure_timeout, receiver).await {
Ok(inner) => match inner {
Ok(value) => value,
Err(_) => Err(SpacetimeClientError::ConnectDropped),
},
Err(_) => Err(Self::resolve_timeout_error(Some(connection))),
}
} else {
Err(SpacetimeClientError::Runtime(
"SpacetimeDB 连接租约缺少连接".to_string(),
))
};
self.release_connection(lease).await;
result
}
} else {
Err(SpacetimeClientError::Runtime(
"SpacetimeDB 连接租约缺少连接".to_string(),
))
Err(error) => Err(error),
};
self.release_connection(lease).await;
metrics_guard.finish(&final_result);
final_result
}
@@ -488,7 +523,6 @@ impl SpacetimeClient {
let mut subscriptions = Vec::new();
for query in [
"SELECT * FROM puzzle_gallery_view",
"SELECT * FROM public_work_play_daily_stat WHERE source_type = 'puzzle'",
] {
let (sender, receiver) = oneshot::channel::<Result<(), SpacetimeClientError>>();
let applied_sender = Arc::new(Mutex::new(Some(sender)));