1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! Scope-level statistics for monitoring consensus activity.
use crate::{
events::ConsensusEventBus, scope::ConsensusScope, service::ConsensusService,
session::ConsensusState, storage::ConsensusStorage,
};
/// Aggregate counters for all sessions within a single scope.
#[derive(Debug, Clone)]
pub struct ConsensusStats {
/// Total number of proposals in this scope.
pub total_sessions: usize,
/// How many proposals are still accepting votes.
pub active_sessions: usize,
/// How many proposals failed to reach consensus (timeout with insufficient votes).
pub failed_sessions: usize,
/// How many proposals successfully reached consensus.
pub consensus_reached: usize,
}
impl<Scope, S, E> ConsensusService<Scope, S, E>
where
Scope: ConsensusScope,
S: ConsensusStorage<Scope>,
E: ConsensusEventBus<Scope>,
{
/// Get statistics about proposals in a scope.
///
/// Returns counts of total, active, failed, and finalized proposals.
/// Useful for monitoring and dashboards.
pub async fn get_scope_stats(&self, scope: &Scope) -> ConsensusStats {
self.list_scope_sessions(scope)
.await
.map(|scope_sessions| {
let total_sessions = scope_sessions.len();
let active_sessions = scope_sessions.iter().filter(|s| s.is_active()).count();
let consensus_reached = scope_sessions
.iter()
.filter(|s| matches!(s.state, ConsensusState::ConsensusReached(_)))
.count();
let failed_sessions = scope_sessions
.iter()
.filter(|s| matches!(s.state, ConsensusState::Failed))
.count();
ConsensusStats {
total_sessions,
active_sessions,
consensus_reached,
failed_sessions,
}
})
.unwrap_or(ConsensusStats {
total_sessions: 0,
active_sessions: 0,
consensus_reached: 0,
failed_sessions: 0,
})
}
}