use std::time::Duration;
use serde::{Deserialize, Serialize};
pub const DEFAULT_RAFT_READY_TIMEOUT_MS: u64 = 30_000;
pub const DEFAULT_DATA_GROUP_RECOVERY_TIMEOUT_MS: u64 = 60_000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RaftReadyTimeout(pub Duration);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DataGroupRecoveryTimeout(pub Duration);
impl From<Duration> for RaftReadyTimeout {
fn from(value: Duration) -> Self {
Self(value)
}
}
impl From<Duration> for DataGroupRecoveryTimeout {
fn from(value: Duration) -> Self {
Self(value)
}
}
fn default_raft_ready_timeout_ms() -> u64 {
DEFAULT_RAFT_READY_TIMEOUT_MS
}
fn default_data_group_recovery_timeout_ms() -> u64 {
DEFAULT_DATA_GROUP_RECOVERY_TIMEOUT_MS
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct StartupTuning {
#[serde(default = "default_raft_ready_timeout_ms")]
pub raft_ready_timeout_ms: u64,
#[serde(default = "default_data_group_recovery_timeout_ms")]
pub data_group_recovery_timeout_ms: u64,
}
impl Default for StartupTuning {
fn default() -> Self {
Self {
raft_ready_timeout_ms: default_raft_ready_timeout_ms(),
data_group_recovery_timeout_ms: default_data_group_recovery_timeout_ms(),
}
}
}
impl StartupTuning {
pub fn raft_ready_timeout(&self) -> RaftReadyTimeout {
RaftReadyTimeout(Duration::from_millis(self.raft_ready_timeout_ms))
}
pub fn data_group_recovery_timeout(&self) -> DataGroupRecoveryTimeout {
DataGroupRecoveryTimeout(Duration::from_millis(self.data_group_recovery_timeout_ms))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn defaults_are_thirty_and_sixty_seconds() {
let cfg = StartupTuning::default();
assert_eq!(
cfg.raft_ready_timeout(),
RaftReadyTimeout(Duration::from_secs(30))
);
assert_eq!(
cfg.data_group_recovery_timeout(),
DataGroupRecoveryTimeout(Duration::from_secs(60))
);
}
#[test]
fn one_bound_set_leaves_the_other_at_its_default() {
let cfg: StartupTuning =
toml::from_str("raft_ready_timeout_ms = 1234").expect("deserialize");
assert_eq!(cfg.raft_ready_timeout_ms, 1234);
assert_eq!(
cfg.data_group_recovery_timeout_ms,
DEFAULT_DATA_GROUP_RECOVERY_TIMEOUT_MS
);
}
#[test]
fn an_unknown_key_is_refused() {
let error = toml::from_str::<StartupTuning>("data_group_recovery_timeout = 1800000")
.expect_err("a key without the _ms suffix is not a bound");
let message = error.to_string();
assert!(message.contains("data_group_recovery_timeout"), "{message}");
assert!(
message.contains("data_group_recovery_timeout_ms"),
"the message must list the keys that exist: {message}"
);
}
}