133 lines
4.5 KiB
Rust
133 lines
4.5 KiB
Rust
// 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(),
|
||
}
|
||
}
|
||
}
|