futrum/src/consensus/raft.rs
2025-10-01 23:13:46 +03:00

133 lines
4.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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(),
}
}
}