refactor: centralize startup readiness bootstrap (#3446)

This commit is contained in:
安正超
2026-06-14 21:24:07 +08:00
committed by GitHub
parent 8d23ce06c6
commit b49057c8e3
4 changed files with 134 additions and 48 deletions
+7 -9
View File
@@ -52,7 +52,7 @@ use crate::server::{
ShutdownHandle, init_event_notifier, shutdown_event_notifier, start_audit_system, start_http_server, stop_audit_system,
};
use crate::startup_fs_guard::enforce_unsupported_fs_policy;
use crate::startup_iam::{IamBootstrapDisposition, bootstrap_or_defer_iam_init};
use crate::startup_iam::{bootstrap_or_defer_iam_init, publish_ready_for_iam_bootstrap};
use rustfs_common::{GlobalReadiness, SystemStage, set_global_addr};
use rustfs_credentials::init_global_action_credentials;
use rustfs_ecstore::store::init_lock_clients;
@@ -494,14 +494,12 @@ impl RustFSServerBuilder {
);
}
if iam_bootstrap == IamBootstrapDisposition::ReadyInline {
crate::server::publish_ready_when_runtime_ready(readiness.as_ref(), None)
.await
.map_err(|e| {
shutdown_embedded_server();
ServerError::Init(format!("runtime readiness: {e}"))
})?;
}
publish_ready_for_iam_bootstrap(iam_bootstrap, readiness.as_ref(), None)
.await
.map_err(|e| {
shutdown_embedded_server();
ServerError::Init(format!("runtime readiness: {e}"))
})?;
rustfs_common::set_global_init_time_now().await;
+2 -4
View File
@@ -34,7 +34,7 @@ use rustfs::server::{
start_audit_system, start_http_server, stop_audit_system, wait_for_shutdown,
};
use rustfs::startup_fs_guard::enforce_unsupported_fs_policy;
use rustfs::startup_iam::{IamBootstrapDisposition, bootstrap_or_defer_iam_init};
use rustfs::startup_iam::{bootstrap_or_defer_iam_init, publish_ready_for_iam_bootstrap};
use rustfs_common::{GlobalReadiness, SystemStage, set_global_addr};
use rustfs_credentials::init_global_action_credentials;
use rustfs_ecstore::store::init_lock_clients;
@@ -968,9 +968,7 @@ async fn run(config: rustfs::config::Config) -> Result<()> {
iam_bootstrap = ?iam_bootstrap,
"RustFS server ready"
);
if iam_bootstrap == IamBootstrapDisposition::ReadyInline {
rustfs::server::publish_ready_when_runtime_ready(readiness.as_ref(), Some(state_manager.as_ref())).await?;
}
publish_ready_for_iam_bootstrap(iam_bootstrap, readiness.as_ref(), Some(state_manager.as_ref())).await?;
// Set the global RustFS initialization time to now
rustfs_common::set_global_init_time_now().await;
+74 -2
View File
@@ -44,6 +44,33 @@ pub enum IamBootstrapDisposition {
Deferred,
}
pub async fn publish_ready_for_iam_bootstrap(
disposition: IamBootstrapDisposition,
readiness: &GlobalReadiness,
state_manager: Option<&ServiceStateManager>,
) -> Result<bool> {
publish_ready_for_iam_bootstrap_with(disposition, || async move {
publish_ready_when_runtime_ready(readiness, state_manager).await
})
.await
}
async fn publish_ready_for_iam_bootstrap_with<PublishFn, PublishFuture>(
disposition: IamBootstrapDisposition,
publish_ready: PublishFn,
) -> Result<bool>
where
PublishFn: FnOnce() -> PublishFuture,
PublishFuture: Future<Output = Result<()>>,
{
if disposition == IamBootstrapDisposition::ReadyInline {
publish_ready().await?;
return Ok(true);
}
Ok(false)
}
fn init_app_context_if_needed(store: Arc<ECStore>, kms_interface: Arc<KmsServiceManager>) -> bool {
if get_global_app_context().is_some() {
return false;
@@ -341,8 +368,8 @@ pub async fn bootstrap_or_defer_iam_init(
#[cfg(test)]
mod tests {
use super::{
IAM_RETRY_ESCALATION_THRESHOLD, IAM_RETRY_INITIAL_INTERVAL, IAM_RETRY_MAX_INTERVAL, compute_backoff_interval,
run_iam_recovery_loop,
IAM_RETRY_ESCALATION_THRESHOLD, IAM_RETRY_INITIAL_INTERVAL, IAM_RETRY_MAX_INTERVAL, IamBootstrapDisposition,
compute_backoff_interval, publish_ready_for_iam_bootstrap_with, run_iam_recovery_loop,
};
use rustfs_common::{GlobalReadiness, SystemStage};
use std::io::Error;
@@ -377,6 +404,51 @@ mod tests {
assert_eq!(compute_backoff_interval(100, initial, max), Duration::from_secs(30));
}
#[tokio::test]
async fn ready_inline_bootstrap_publishes_runtime_readiness() {
let publish_calls = Arc::new(AtomicUsize::new(0));
let publish_calls_for_assert = publish_calls.clone();
let published = publish_ready_for_iam_bootstrap_with(IamBootstrapDisposition::ReadyInline, move || async move {
publish_calls.fetch_add(1, Ordering::SeqCst);
Ok(())
})
.await;
assert!(published.is_ok(), "ready inline publication should succeed");
let published = published.unwrap_or(false);
assert!(published);
assert_eq!(publish_calls_for_assert.load(Ordering::SeqCst), 1);
}
#[tokio::test]
async fn deferred_bootstrap_skips_runtime_readiness_publication() {
let publish_calls = Arc::new(AtomicUsize::new(0));
let publish_calls_for_assert = publish_calls.clone();
let published = publish_ready_for_iam_bootstrap_with(IamBootstrapDisposition::Deferred, move || async move {
publish_calls.fetch_add(1, Ordering::SeqCst);
Ok(())
})
.await;
assert!(published.is_ok(), "deferred publication should be a no-op");
let published = published.unwrap_or(true);
assert!(!published);
assert_eq!(publish_calls_for_assert.load(Ordering::SeqCst), 0);
}
#[tokio::test]
async fn ready_inline_bootstrap_propagates_runtime_readiness_failure() {
let err = publish_ready_for_iam_bootstrap_with(IamBootstrapDisposition::ReadyInline, || async {
Err(Error::other("runtime readiness failed"))
})
.await
.expect_err("ready inline publication failure should be returned");
assert_eq!(err.to_string(), "runtime readiness failed");
}
#[tokio::test(start_paused = true)]
async fn recovery_loop_retries_finalize_until_success() {
let init_calls = Arc::new(AtomicUsize::new(0));