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