mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-31 09:18:28 +00:00
Inject GlobalReadiness into HTTP server pipeline and gate traffic until FullReady (#1255)
This commit is contained in:
@@ -37,6 +37,7 @@ use rustfs_policy::{
|
||||
use rustfs_utils::path::path_join_buf;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::sync::atomic::AtomicU8;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::{
|
||||
@@ -76,9 +77,19 @@ fn get_iam_format_file_path() -> String {
|
||||
path_join_buf(&[&IAM_CONFIG_PREFIX, IAM_FORMAT_FILE])
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum IamState {
|
||||
Uninitialized = 0,
|
||||
Loading = 1,
|
||||
Ready = 2,
|
||||
Error = 3,
|
||||
}
|
||||
|
||||
pub struct IamCache<T> {
|
||||
pub cache: Cache,
|
||||
pub api: T,
|
||||
pub state: Arc<AtomicU8>,
|
||||
pub loading: Arc<AtomicBool>,
|
||||
pub roles: HashMap<ARN, Vec<String>>,
|
||||
pub send_chan: Sender<i64>,
|
||||
@@ -89,12 +100,19 @@ impl<T> IamCache<T>
|
||||
where
|
||||
T: Store,
|
||||
{
|
||||
/// Create a new IAM system instance
|
||||
/// # Arguments
|
||||
/// * `api` - The storage backend implementing the Store trait
|
||||
///
|
||||
/// # Returns
|
||||
/// An Arc-wrapped instance of IamSystem
|
||||
pub(crate) async fn new(api: T) -> Arc<Self> {
|
||||
let (sender, receiver) = mpsc::channel::<i64>(100);
|
||||
|
||||
let sys = Arc::new(Self {
|
||||
api,
|
||||
cache: Cache::default(),
|
||||
state: Arc::new(AtomicU8::new(IamState::Uninitialized as u8)),
|
||||
loading: Arc::new(AtomicBool::new(false)),
|
||||
send_chan: sender,
|
||||
roles: HashMap::new(),
|
||||
@@ -105,10 +123,32 @@ where
|
||||
sys
|
||||
}
|
||||
|
||||
/// Initialize the IAM system
|
||||
async fn init(self: Arc<Self>, receiver: Receiver<i64>) -> Result<()> {
|
||||
self.state.store(IamState::Loading as u8, Ordering::SeqCst);
|
||||
// Ensure the IAM format file is persisted first
|
||||
self.clone().save_iam_formatter().await?;
|
||||
self.clone().load().await?;
|
||||
|
||||
// Critical: Load all existing users/policies into memory cache
|
||||
const MAX_RETRIES: usize = 3;
|
||||
for attempt in 0..MAX_RETRIES {
|
||||
if let Err(e) = self.clone().load().await {
|
||||
if attempt == MAX_RETRIES - 1 {
|
||||
self.state.store(IamState::Error as u8, Ordering::SeqCst);
|
||||
error!("IAM fail to load initial data after {} attempts: {:?}", MAX_RETRIES, e);
|
||||
return Err(e);
|
||||
} else {
|
||||
warn!("IAM load failed, retrying... attempt {}", attempt + 1);
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.state.store(IamState::Ready as u8, Ordering::SeqCst);
|
||||
info!("IAM System successfully initialized and marked as READY");
|
||||
|
||||
// Background ticker for synchronization
|
||||
// Check if environment variable is set
|
||||
let skip_background_task = std::env::var("RUSTFS_SKIP_BACKGROUND_TASK").is_ok();
|
||||
|
||||
@@ -152,6 +192,11 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check if IAM system is ready
|
||||
pub fn is_ready(&self) -> bool {
|
||||
self.state.load(Ordering::SeqCst) == IamState::Ready as u8
|
||||
}
|
||||
|
||||
async fn _notify(&self) {
|
||||
self.send_chan.send(OffsetDateTime::now_utc().unix_timestamp()).await.unwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user