futrum/src/consensus/raft.rs

133 lines
4.5 KiB
Rust
Raw Normal View History

2025-10-01 23:13:46 +03:00
// src/consensus/raft.rs
use super::state::{RaftState, NodeState};
use crate::FutrumError;
use std::sync::Arc;
use tokio::sync::RwLock;
use tokio::time::Duration;
use uuid::Uuid;
use rand;
pub struct RaftConsensus {
state: Arc<RwLock<RaftState>>,
node_id: String,
peers: Vec<String>,
election_timeout: Duration,
heartbeat_interval: Duration,
enabled: bool,
should_stop: Arc<RwLock<bool>>,
}
impl RaftConsensus {
pub fn new(enabled: bool, election_timeout_ms: u64, heartbeat_interval_ms: u64) -> Result<Self, FutrumError> {
let node_id = Uuid::new_v4().to_string();
Ok(Self {
state: Arc::new(RwLock::new(RaftState::new(node_id.clone()))),
node_id,
peers: Vec::new(),
election_timeout: Duration::from_millis(election_timeout_ms),
heartbeat_interval: Duration::from_millis(heartbeat_interval_ms),
enabled,
should_stop: Arc::new(RwLock::new(false)),
})
}
// Тихая версия запуска - БЕЗ ВЫВОДА В КОНСОЛЬ
pub async fn start_silent(&self) -> Result<(), FutrumError> {
if !self.enabled {
return Ok(());
}
let state = self.state.clone();
let node_id = self.node_id.clone();
let should_stop = self.should_stop.clone();
let election_timeout = self.election_timeout;
let heartbeat_interval = self.heartbeat_interval;
tokio::spawn(async move {
let mut iteration_count = 0;
while !*should_stop.read().await {
iteration_count += 1;
// ОГРАНИЧИВАЕМ активность - работаем только каждые 100 итераций
if iteration_count % 100 != 0 {
tokio::time::sleep(Duration::from_millis(10)).await;
continue;
}
let current_state = { state.read().await.current_state };
match current_state {
NodeState::Follower => {
if Self::should_start_election_silent(&should_stop).await && !*should_stop.read().await {
state.write().await.current_state = NodeState::Candidate;
}
}
NodeState::Candidate => {
if !*should_stop.read().await {
let _ = Self::start_election_silent(state.clone()).await;
}
}
NodeState::Leader => {
// Минимальная активность в режиме лидера
}
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
});
Ok(())
}
async fn should_start_election_silent(should_stop: &Arc<RwLock<bool>>) -> bool {
// Увеличиваем таймаут для уменьшения активности
let timeout = rand::random::<u64>() % 1000 + 500; // 500-1500ms вместо 150-450ms
tokio::time::sleep(Duration::from_millis(timeout.min(100))).await;
true
}
async fn start_election_silent(state: Arc<RwLock<RaftState>>) -> Result<(), FutrumError> {
let mut state_guard = state.write().await;
state_guard.current_term += 1;
state_guard.voted_for = Some(state_guard.node_id.clone());
state_guard.vote_count = 1;
if state_guard.vote_count > 0 {
state_guard.current_state = NodeState::Leader;
}
Ok(())
}
pub async fn is_leader(&self) -> bool {
if !self.enabled {
return false;
}
self.state.read().await.current_state == NodeState::Leader
}
pub async fn get_current_term(&self) -> u64 {
self.state.read().await.current_term
}
pub async fn stop(&self) {
*self.should_stop.write().await = true;
}
}
impl Clone for RaftConsensus {
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
node_id: self.node_id.clone(),
peers: self.peers.clone(),
election_timeout: self.election_timeout,
heartbeat_interval: self.heartbeat_interval,
enabled: self.enabled,
should_stop: self.should_stop.clone(),
}
}
}