unc_chain_configs/
updateable_config.rs

1use serde::{Deserialize, Serialize, Serializer};
2use std::sync::{Arc, Mutex};
3use std::{fmt::Debug, time::Duration};
4use unc_primitives::types::BlockHeight;
5
6use crate::ReshardingConfig;
7
8/// A wrapper for a config value that can be updated while the node is running.
9/// When initializing sub-objects (e.g. `ShardsManager`), please make sure to
10/// pass this wrapper instead of passing a value from a single moment in time.
11/// See `expected_shutdown` for an example how to use it.
12#[derive(Clone, Debug)]
13pub struct MutableConfigValue<T> {
14    value: Arc<Mutex<T>>,
15    // For metrics.
16    // Mutable config values are exported to prometheus with labels [field_name][last_update][value].
17    field_name: String,
18    #[cfg(feature = "metrics")]
19    // For metrics.
20    // Mutable config values are exported to prometheus with labels [field_name][last_update][value].
21    last_update: chrono::DateTime<chrono::Utc>,
22}
23
24impl<T: Serialize> Serialize for MutableConfigValue<T> {
25    /// Only include the value field of MutableConfigValue in serialized result
26    /// since field_name and last_update are only relevant for internal monitoring
27    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
28    where
29        S: Serializer,
30    {
31        let to_string_result = serde_json::to_string(&self.value);
32        let value_str = to_string_result.unwrap_or("unable to serialize the value".to_string());
33        serializer.serialize_str(&value_str)
34    }
35}
36
37impl<T: Copy + PartialEq + Debug> MutableConfigValue<T> {
38    /// Initializes a value.
39    /// `field_name` is needed to export the config value as a prometheus metric.
40    pub fn new(val: T, field_name: &str) -> Self {
41        let res = Self {
42            value: Arc::new(Mutex::new(val)),
43            field_name: field_name.to_string(),
44            #[cfg(feature = "metrics")]
45            last_update: unc_primitives::static_clock::StaticClock::utc(),
46        };
47        res.set_metric_value(val, 1);
48        res
49    }
50
51    pub fn get(&self) -> T {
52        *self.value.lock().unwrap()
53    }
54
55    pub fn update(&self, val: T) {
56        let mut lock = self.value.lock().unwrap();
57        if *lock != val {
58            tracing::info!(target: "config", "Updated config field '{}' from {:?} to {:?}", self.field_name, *lock, val);
59            self.set_metric_value(*lock, 0);
60            *lock = val;
61            self.set_metric_value(val, 1);
62        } else {
63            tracing::info!(target: "config", "Mutable config field '{}' remains the same: {:?}", self.field_name, val);
64        }
65    }
66
67    #[cfg(feature = "metrics")]
68    fn set_metric_value(&self, value: T, metric_value: i64) {
69        // Use field_name as a label to tell different mutable config values apart.
70        // Use timestamp as a label to give some idea to the node operator (or
71        // people helping them debug their node) when exactly and what values
72        // exactly were part of the config.
73        // Use the config value as a label to make this work with config values
74        // of any type: int, float, string or even a composite object.
75        crate::metrics::CONFIG_MUTABLE_FIELD
76            .with_label_values(&[
77                &self.field_name,
78                &self.last_update.timestamp().to_string(),
79                &format!("{:?}", value),
80            ])
81            .set(metric_value);
82    }
83
84    #[cfg(not(feature = "metrics"))]
85    fn set_metric_value(&self, _value: T, _metric_value: i64) {}
86}
87
88#[derive(Default, Clone, Serialize, Deserialize)]
89/// A subset of Config that can be updated white the node is running.
90pub struct UpdateableClientConfig {
91    /// Graceful shutdown at expected block height.
92    pub expected_shutdown: Option<BlockHeight>,
93
94    // Configuration for resharding.
95    pub resharding_config: ReshardingConfig,
96
97    /// Time limit for adding transactions in produce_chunk()
98    pub produce_chunk_add_transactions_time_limit: Option<Duration>,
99}