clementine_core/task/
entity_metric_publisher.rs1use std::sync::LazyLock;
2use std::time::Duration;
3
4use tonic::async_trait;
5
6use crate::metrics::SyncStatusProvider;
7
8use crate::{
9 citrea::CitreaClientT,
10 database::Database,
11 extended_bitcoin_rpc::ExtendedBitcoinRpc,
12 metrics::ENTITY_SYNC_STATUS,
13 task::{Task, TaskVariant},
14 utils::NamedEntity,
15};
16use clementine_errors::BridgeError;
17
18pub const ENTITY_METRIC_PUBLISHER_INTERVAL: Duration = Duration::from_secs(120);
23
24#[derive(Debug, Clone)]
25pub struct EntityMetricPublisher<T: NamedEntity, C: CitreaClientT> {
27 db: Database,
28 rpc: ExtendedBitcoinRpc,
29 config: crate::config::BridgeConfig,
30 citrea_client: C,
31 _phantom: std::marker::PhantomData<T>,
32}
33
34impl<T: NamedEntity, C: CitreaClientT> EntityMetricPublisher<T, C> {
35 pub fn new(
36 db: Database,
37 rpc: ExtendedBitcoinRpc,
38 config: crate::config::BridgeConfig,
39 citrea_client: C,
40 ) -> Self {
41 Self {
42 db,
43 rpc,
44 config,
45 citrea_client,
46 _phantom: std::marker::PhantomData,
47 }
48 }
49}
50
51#[async_trait]
52impl<T: NamedEntity, C: CitreaClientT> Task for EntityMetricPublisher<T, C> {
53 const VARIANT: TaskVariant = TaskVariant::MetricPublisher;
54 type Output = bool;
55
56 async fn run_once(&mut self) -> Result<Self::Output, BridgeError> {
57 if cfg!(test) {
59 return Ok(false);
60 }
61
62 let sync_status = match T::get_sync_status(
63 &self.db,
64 &self.rpc,
65 &self.config,
66 &self.citrea_client,
67 )
68 .await
69 {
70 Ok(sync_status) => sync_status,
71 Err(e) => {
72 tracing::error!(
73 "Failed to get status when publishing metrics for {}: {:?}",
74 T::ENTITY_NAME,
75 e
76 );
77
78 return Ok(false);
79 }
80 };
81
82 let metric = LazyLock::force(&ENTITY_SYNC_STATUS);
83
84 if let Some(balance) = sync_status.wallet_balance {
85 metric.wallet_balance_btc.set(balance.to_btc());
86 }
87 if let Some(height) = sync_status.rpc_tip_height {
88 metric.rpc_tip_height.set(height as f64);
89 }
90 if let Some(height) = sync_status.hcp_last_proven_height {
91 metric.hcp_last_proven_height.set(height as f64);
92 }
93 if let Some(height) = sync_status.btc_syncer_synced_height {
94 metric.btc_syncer_synced_height.set(height as f64);
95 }
96 if let Some(height) = sync_status.finalized_synced_height {
97 metric.finalized_synced_height.set(height as f64);
98 }
99 if let Some(height) = sync_status.tx_sender_synced_height {
100 metric.tx_sender_synced_height.set(height as f64);
101 }
102 if let Some(height) = sync_status.state_manager_next_height {
103 metric.state_manager_next_height.set(height as f64);
104 }
105 if let Some(fee_rate) = sync_status.bitcoin_fee_rate_sat_vb {
106 metric.bitcoin_fee_rate_sat_vb.set(fee_rate as f64);
107 }
108 if let Some(height) = sync_status.lcp_synced_height {
109 metric.lcp_synced_height.set(height as f64);
110 }
111 if let Some(height) = sync_status.citrea_l2_block_height {
112 metric.citrea_l2_block_height.set(height as f64);
113 }
114
115 Ok(false)
116 }
117}