refactor: remove optional runtime handle fallbacks (#3952)

This commit is contained in:
Zhengchao An
2026-06-27 18:07:09 +08:00
committed by GitHub
parent 430aa8e8cb
commit d66391636b
2 changed files with 87 additions and 98 deletions
+37 -16
View File
@@ -5,7 +5,7 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
## Current Context
- Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660)
- Branch: `overtrue/arch-runtime-notification-config-fallback-removal`
- Branch: `overtrue/arch-runtime-optional-handle-fallback-removal`
- Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093/API-094/API-095/API-096/API-097/API-098/API-099/API-100/API-101/API-102/API-103/API-104/API-105/API-106/API-107/API-108/API-109/API-110/API-111/API-112/API-113/API-114/API-115/API-116/API-117/API-118/API-119/API-120/API-121/API-122/API-123/API-124/API-125/API-126/API-127/API-128/API-129/API-130/API-131/API-132/API-133/API-134/API-135/API-136/API-137/API-138/API-139/API-140/API-141/API-142/API-143/API-144/API-145/API-146/API-147/API-148/API-149/API-150/API-151/API-152/API-153/API-154/API-155/API-156/API-157/API-158/API-159/API-160/API-161/API-162/API-163/API-164/API-165/API-166/API-167/API-168/API-169/API-170/API-171/API-172/API-173/API-174/API-175/API-176/API-177/API-178/API-179/API-180/API-181/API-182/API-183/API-184/API-185/API-186/API-187/API-188/API-189/API-190/API-191/API-192/API-193/API-194/API-195/API-196/API-197/API-198/API-199/API-200/API-201/API-202/API-203/API-204/API-205/API-206/API-207/API-208/API-209/API-210/API-211/API-212/API-213/API-214/API-215/API-216/API-217/API-218/API-219/API-220/API-221/API-222/API-223/API-224/API-225/API-226/API-227/API-228/API-229/API-230/API-231/API-232/API-233/API-234/API-235/API-236/API-237/API-238/API-239/API-240/API-241/API-242/API-243/API-244/API-245/API-246/API-247/API-248/API-249/API-250/API-251/API-252/API-253/API-254/CTX-002`.
- Current baseline also includes API-255 from PR #3923, API-256 from PR
#3925, CFG-009 from PR #3927, C-007/C-009 from PR #3935, C-008/C-010
@@ -16,23 +16,23 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
GLOB-007 admin object-store/notification/server-config consumer batch from
PR #3943, the GLOB-007 admin runtime helper alias batch from PR #3944, the
GLOB-007 storage/server runtime facade consumer batch from PR #3946, the
GLOB-007 app runtime facade consumer batch from PR #3947, the pending
GLOB-007 core runtime facade consumer batch from PR #3948, and the
GLOB-007 runtime facade alias sweep merged into that base branch from
PR #3949, and the GLOB-007 object-store fallback removal from PR #3950,
which is merged into that pending base branch.
- Current phase PR: GLOB-007 notification-system/server-config fallback removal.
- Based on: `overtrue/arch-global-core-runtime-consumer-batch` after PR #3950
was merged into that branch while PR #3948 is pending.
GLOB-007 app runtime facade consumer batch from PR #3947, the GLOB-007 core
runtime facade consumer batch from PR #3948, the GLOB-007 runtime facade
alias sweep from PR #3949, the GLOB-007 object-store fallback removal from
PR #3950, and the GLOB-007 notification-system/server-config fallback
removal from PR #3951.
- Current phase PR: GLOB-007 optional runtime handle fallback removal.
- Based on: `origin/main` after PR #3951 merged.
- PR type for this branch: `ci-gate`.
- Runtime behavior changes: notification-system and server-config read paths
now require AppContext instead of falling back to legacy globals; server-config
publish keeps the no-context startup write path.
- Rust code changes: remove the legacy global notification-system and
server-config read fallbacks from the AppContext resolver family.
- Runtime behavior changes: optional runtime reads for token signing key,
bucket metadata, endpoint pools, bucket monitor, replication handles, boot
time, deployment ID, lock clients, and region now require AppContext instead
of falling back to legacy globals.
- Rust code changes: remove the legacy global fallbacks from those optional
AppContext resolver families.
- CI/script changes: none intended.
- Docs changes: update this progress ledger for the notification-system and
server-config fallback removal.
- Docs changes: update this progress ledger for the optional handle fallback
removal.
## Phase 0 Tasks
@@ -2816,6 +2816,10 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
- Current slice: remove the legacy global notification-system and
server-config read fallbacks from the AppContext resolver family while
preserving the server-config publish path used during startup.
- Current slice: remove the legacy global fallbacks from optional runtime
handle/read resolvers for token signing key, bucket metadata, endpoints,
bucket monitor, replication handles, boot time, deployment ID, lock
clients, and region.
- Remaining work: remove the next fallback family per PR only after scans
prove no production caller depends on it.
- Verification: focused RustFS compile and admin test-target compile,
@@ -6084,6 +6088,9 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
| Expert | Status | Notes |
|---|---|---|
| Quality/architecture | pass | GLOB-007 removes a broad optional-handle resolver fallback batch, keeping absent AppContext from consulting legacy globals for token signing key, bucket metadata, endpoints, bucket monitor, replication, boot, deployment, lock, and region reads. |
| Migration preservation | pass | Action credentials, concrete default-returning runtime families, startup publishers, KMS/TLS/IAM readiness initialization, scanner metrics, S3 Select, local node name, tier config, expiry state, performance metrics, and buffer config fallbacks are intentionally left unchanged for later slices. |
| Testing/verification | pass | Focused RustFS compile/test, formatting, architecture guard, optional-handle fallback residual scan, diff hygiene, diff-added Rust risk scan, and full `make pre-pr` are required before PR. |
| Quality/architecture | pass | GLOB-007 removes the notification-system and server-config resolver read fallbacks, keeping no-context reads from consulting legacy globals while preserving explicit AppContext interfaces. |
| Migration preservation | pass | Server-config publishing keeps the no-context startup write path; notification-system and server-config consumers already route through current runtime facades, so initialized AppContext behavior remains unchanged. |
| Testing/verification | pass | Focused RustFS compile, formatting, architecture guard, notification/server-config fallback residual scan, diff hygiene, diff-added Rust risk scan, and full `make pre-pr` passed before PR. |
@@ -6468,6 +6475,20 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
Passed before push:
- Issue #660 GLOB-007 optional runtime handle fallback removal:
- Branch freshness check: rebased onto `origin/main` after PR #3951 merged.
- `cargo test -p rustfs --lib app::context::tests::resolver_helpers_are_context_first_and_fallback_when_context_is_absent`:
passed.
- `cargo check -p rustfs --lib`: passed.
- `cargo fmt --all`: passed.
- `cargo fmt --all --check`: passed.
- `git diff --check`: passed.
- `./scripts/check_architecture_migration_rules.sh`: passed.
- Optional-handle fallback residual scan: passed.
- Diff-added Rust risk scan: passed.
- Three-expert review: passed.
- `make pre-pr`: passed (`nextest`: 6917 passed, 112 skipped; doctests passed).
- Issue #660 GLOB-007 notification-system/server-config fallback removal:
- Branch freshness check: prepared from
`overtrue/arch-runtime-object-store-fallback-removal`, then based on
+50 -82
View File
@@ -102,12 +102,12 @@ pub fn resolve_ready_iam_handle() -> rustfs_iam::error::Result<Arc<IamSys<Object
/// Resolve token signing key using AppContext-first precedence.
pub fn resolve_token_signing_key() -> Option<String> {
resolve_token_signing_key_with(get_global_app_context(), runtime_sources::token_signing_key)
resolve_token_signing_key_with(get_global_app_context(), || None)
}
/// Resolve bucket metadata handle using AppContext-first precedence.
pub fn resolve_bucket_metadata_handle() -> Option<Arc<RwLock<BucketMetadataSys>>> {
resolve_bucket_metadata_handle_with(get_global_app_context(), || default_bucket_metadata_interface().handle())
resolve_bucket_metadata_handle_with(get_global_app_context(), || None)
}
/// Resolve object store handle using AppContext-first precedence.
@@ -146,27 +146,27 @@ pub fn resolve_notification_system_for_context(context: Option<&AppContext>) ->
/// Resolve endpoints using AppContext-first precedence.
pub fn resolve_endpoints_handle() -> Option<EndpointServerPools> {
resolve_endpoints_handle_with(get_global_app_context(), || default_endpoints_interface().handle())
resolve_endpoints_handle_with(get_global_app_context(), || None)
}
/// Resolve bucket bandwidth monitor using AppContext-first precedence.
pub fn resolve_bucket_monitor_handle() -> Option<Arc<BucketBandwidthMonitor>> {
resolve_bucket_monitor_handle_with(get_global_app_context(), || default_bucket_monitor_interface().handle())
resolve_bucket_monitor_handle_with(get_global_app_context(), || None)
}
/// Resolve replication pool handle using AppContext-first precedence.
pub fn resolve_replication_pool_handle() -> Option<Arc<DynReplicationPool>> {
resolve_replication_pool_handle_with(get_global_app_context(), || default_replication_pool_interface().handle())
resolve_replication_pool_handle_with(get_global_app_context(), || None)
}
/// Resolve replication statistics handle using AppContext-first precedence.
pub fn resolve_replication_stats_handle() -> Option<Arc<ReplicationStats>> {
resolve_replication_stats_handle_with(get_global_app_context(), || default_replication_stats_interface().handle())
resolve_replication_stats_handle_with(get_global_app_context(), || None)
}
/// Resolve boot time using AppContext-first precedence.
pub fn resolve_boot_time() -> Option<SystemTime> {
resolve_boot_time_with(get_global_app_context(), || default_boot_time_interface().get())
resolve_boot_time_with(get_global_app_context(), || None)
}
/// Resolve daily tier transition statistics using AppContext-first precedence.
@@ -182,7 +182,7 @@ pub async fn resolve_scanner_metrics_report() -> ScannerMetricsReport {
/// Resolve deployment identity using AppContext-first precedence.
pub fn resolve_deployment_id() -> Option<String> {
resolve_deployment_id_with(get_global_app_context(), || default_deployment_id_interface().get())
resolve_deployment_id_with(get_global_app_context(), || None)
}
/// Resolve runtime port using AppContext-first precedence.
@@ -192,12 +192,12 @@ pub fn resolve_runtime_port() -> u16 {
/// Resolve lock client using AppContext-first precedence.
pub fn resolve_lock_client() -> Option<Arc<dyn LockClient>> {
resolve_lock_client_with(get_global_app_context(), || default_lock_client_interface().handle())
resolve_lock_client_with(get_global_app_context(), || None)
}
/// Resolve lock clients using AppContext-first precedence.
pub fn resolve_lock_clients_handle() -> Option<HashMap<String, Arc<dyn LockClient>>> {
resolve_lock_clients_handle_with(get_global_app_context(), || default_lock_clients_interface().handle())
resolve_lock_clients_handle_with(get_global_app_context(), || None)
}
/// Resolve performance metrics using AppContext-first precedence.
@@ -233,7 +233,7 @@ pub fn resolve_action_credentials() -> Option<Credentials> {
/// Resolve region using AppContext-first precedence.
pub fn resolve_region() -> Option<s3s::region::Region> {
resolve_region_with(get_global_app_context(), || default_region_interface().get())
resolve_region_with(get_global_app_context(), || None)
}
/// Resolve tier config handle using AppContext-first precedence.
@@ -355,19 +355,18 @@ fn resolve_ready_iam_handle_with(
fallback()
}
fn resolve_token_signing_key_with(context: Option<Arc<AppContext>>, fallback: impl FnOnce() -> Option<String>) -> Option<String> {
context
.and_then(|context| context.iam().token_signing_key())
.or_else(fallback)
fn resolve_token_signing_key_with(
context: Option<Arc<AppContext>>,
_fallback: impl FnOnce() -> Option<String>,
) -> Option<String> {
context.and_then(|context| context.iam().token_signing_key())
}
fn resolve_bucket_metadata_handle_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<Arc<RwLock<BucketMetadataSys>>>,
_fallback: impl FnOnce() -> Option<Arc<RwLock<BucketMetadataSys>>>,
) -> Option<Arc<RwLock<BucketMetadataSys>>> {
context
.and_then(|context| context.bucket_metadata().handle())
.or_else(fallback)
context.and_then(|context| context.bucket_metadata().handle())
}
fn resolve_notification_system_with(
@@ -379,33 +378,30 @@ fn resolve_notification_system_with(
fn resolve_bucket_monitor_handle_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<Arc<BucketBandwidthMonitor>>,
_fallback: impl FnOnce() -> Option<Arc<BucketBandwidthMonitor>>,
) -> Option<Arc<BucketBandwidthMonitor>> {
context
.and_then(|context| context.bucket_monitor().handle())
.or_else(fallback)
context.and_then(|context| context.bucket_monitor().handle())
}
fn resolve_replication_pool_handle_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<Arc<DynReplicationPool>>,
_fallback: impl FnOnce() -> Option<Arc<DynReplicationPool>>,
) -> Option<Arc<DynReplicationPool>> {
context
.and_then(|context| context.replication_pool().handle())
.or_else(fallback)
context.and_then(|context| context.replication_pool().handle())
}
fn resolve_replication_stats_handle_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<Arc<ReplicationStats>>,
_fallback: impl FnOnce() -> Option<Arc<ReplicationStats>>,
) -> Option<Arc<ReplicationStats>> {
context
.and_then(|context| context.replication_stats().handle())
.or_else(fallback)
context.and_then(|context| context.replication_stats().handle())
}
fn resolve_boot_time_with(context: Option<Arc<AppContext>>, fallback: impl FnOnce() -> Option<SystemTime>) -> Option<SystemTime> {
context.and_then(|context| context.boot_time().get()).or_else(fallback)
fn resolve_boot_time_with(
context: Option<Arc<AppContext>>,
_fallback: impl FnOnce() -> Option<SystemTime>,
) -> Option<SystemTime> {
context.and_then(|context| context.boot_time().get())
}
fn resolve_daily_tier_stats_with(
@@ -437,13 +433,13 @@ fn resolve_object_store_handle_with(
fn resolve_endpoints_handle_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<EndpointServerPools>,
_fallback: impl FnOnce() -> Option<EndpointServerPools>,
) -> Option<EndpointServerPools> {
context.and_then(|context| context.endpoints().handle()).or_else(fallback)
context.and_then(|context| context.endpoints().handle())
}
fn resolve_deployment_id_with(context: Option<Arc<AppContext>>, fallback: impl FnOnce() -> Option<String>) -> Option<String> {
context.and_then(|context| context.deployment_id().get()).or_else(fallback)
fn resolve_deployment_id_with(context: Option<Arc<AppContext>>, _fallback: impl FnOnce() -> Option<String>) -> Option<String> {
context.and_then(|context| context.deployment_id().get())
}
fn resolve_runtime_port_with(context: Option<Arc<AppContext>>, fallback: impl FnOnce() -> u16) -> u16 {
@@ -452,16 +448,16 @@ fn resolve_runtime_port_with(context: Option<Arc<AppContext>>, fallback: impl Fn
fn resolve_lock_client_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<Arc<dyn LockClient>>,
_fallback: impl FnOnce() -> Option<Arc<dyn LockClient>>,
) -> Option<Arc<dyn LockClient>> {
context.and_then(|context| context.lock_client().handle()).or_else(fallback)
context.and_then(|context| context.lock_client().handle())
}
fn resolve_lock_clients_handle_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<HashMap<String, Arc<dyn LockClient>>>,
_fallback: impl FnOnce() -> Option<HashMap<String, Arc<dyn LockClient>>>,
) -> Option<HashMap<String, Arc<dyn LockClient>>> {
context.and_then(|context| context.lock_clients().handle()).or_else(fallback)
context.and_then(|context| context.lock_clients().handle())
}
fn resolve_performance_metrics_with(
@@ -518,9 +514,9 @@ fn resolve_action_credentials_with(
fn resolve_region_with(
context: Option<Arc<AppContext>>,
fallback: impl FnOnce() -> Option<s3s::region::Region>,
_fallback: impl FnOnce() -> Option<s3s::region::Region>,
) -> Option<s3s::region::Region> {
context.map(|context| context.region().get()).unwrap_or_else(fallback)
context.and_then(|context| context.region().get())
}
fn resolve_tier_config_handle_with(
@@ -1306,21 +1302,14 @@ mod tests {
assert!(!resolve_iam_ready_with(None, || false));
assert!(resolve_iam_handle_with(None, || None).is_none());
assert!(resolve_oidc_handle_with(None).is_none());
assert!(resolve_token_signing_key_with(None, || Some(fallback_token_signing_key.clone())).is_none());
assert!(!publish_oidc_handle_with(None, context_oidc));
assert!(Arc::ptr_eq(
&resolve_bucket_metadata_handle_with(None, || Some(bucket_metadata.clone())).expect("fallback bucket metadata"),
&bucket_metadata
));
assert!(resolve_bucket_metadata_handle_with(None, || Some(bucket_metadata.clone())).is_none());
assert!(resolve_bucket_monitor_handle_with(None, || default_bucket_monitor_interface().handle()).is_none());
assert!(resolve_replication_pool_handle_with(None, || default_replication_pool_interface().handle()).is_none());
assert!(resolve_object_store_handle_with(None, || Some(object_store.clone())).is_none());
assert!(Arc::ptr_eq(
&resolve_replication_stats_handle_with(None, || Some(fallback_replication_stats.clone()))
.expect("fallback replication stats"),
&fallback_replication_stats
));
assert_eq!(
resolve_boot_time_with(None, || Some(fallback_boot_time)).expect("fallback boot time"),
fallback_boot_time
);
assert!(resolve_replication_stats_handle_with(None, || Some(fallback_replication_stats.clone())).is_none());
assert!(resolve_boot_time_with(None, || Some(fallback_boot_time)).is_none());
assert!(resolve_daily_tier_stats_with(None, || fallback_daily_tier_stats.clone()).contains_key("FALLBACK"));
assert_eq!(
resolve_scanner_metrics_report_with(None, || async { fallback_scanner_metrics.clone() })
@@ -1328,29 +1317,11 @@ mod tests {
.current_cycle,
fallback_scanner_metrics.current_cycle
);
assert_eq!(
resolve_endpoints_handle_with(None, || Some(endpoints.clone()))
.expect("fallback endpoints")
.as_ref()[0]
.drives_per_set,
endpoints.as_ref()[0].drives_per_set
);
assert_eq!(
resolve_deployment_id_with(None, || Some(fallback_deployment_id.clone())).expect("fallback deployment id"),
fallback_deployment_id
);
assert!(resolve_endpoints_handle_with(None, || Some(endpoints.clone())).is_none());
assert!(resolve_deployment_id_with(None, || Some(fallback_deployment_id.clone())).is_none());
assert_eq!(resolve_runtime_port_with(None, || fallback_runtime_port), fallback_runtime_port);
assert!(Arc::ptr_eq(
&resolve_lock_client_with(None, || Some(fallback_lock_client.clone())).expect("fallback lock client"),
&fallback_lock_client
));
assert!(Arc::ptr_eq(
resolve_lock_clients_handle_with(None, || Some(fallback_lock_clients.clone()))
.expect("fallback lock clients")
.get("fallback-node:9000")
.expect("fallback lock client entry"),
&fallback_lock_client
));
assert!(resolve_lock_client_with(None, || Some(fallback_lock_client.clone())).is_none());
assert!(resolve_lock_clients_handle_with(None, || Some(fallback_lock_clients.clone())).is_none());
assert!(Arc::ptr_eq(
&resolve_performance_metrics_with(None, || fallback_performance_metrics.clone()),
&fallback_performance_metrics
@@ -1377,10 +1348,7 @@ mod tests {
.access_key,
fallback_credentials.access_key
);
assert_eq!(
resolve_region_with(None, || Some(fallback_region.clone())).expect("fallback region"),
fallback_region
);
assert!(resolve_region_with(None, || Some(fallback_region.clone())).is_none());
assert!(Arc::ptr_eq(&resolve_tier_config_handle_with(None, || tier_config.clone()), &tier_config));
assert!(Arc::ptr_eq(
&resolve_expiry_state_handle_with(None, || fallback_expiry_state.clone()),