diff --git a/crates/scanner/src/scanner.rs b/crates/scanner/src/scanner.rs index 08c0633fe..3d2a50f73 100644 --- a/crates/scanner/src/scanner.rs +++ b/crates/scanner/src/scanner.rs @@ -964,9 +964,10 @@ async fn run_scanner_usage_recovery_intents_for_startup( Ok(attempted) } -/// Start normal scanning when enabled, or one resume-only cleanup attempt. +/// Start normal scanning when enabled, or one bounded recovery attempt. /// The disabled branch returns a finite task for the startup owner to join; -/// it never enables ordinary namespace scanning or accepts a new reset intent. +/// it never enables ordinary namespace scanning while it replays durable reset +/// intents and cleanup markers. pub async fn init_scanner_with_recovery( ctx: CancellationToken, storeapi: Arc, @@ -988,6 +989,17 @@ pub async fn init_scanner_with_recovery( return None; } Some(tokio::spawn(async move { + if let Err(error) = run_scanner_usage_recovery_intents_for_startup(ctx.clone(), storeapi.clone()).await { + warn!( + target: "rustfs::scanner", + event = EVENT_SCANNER_PERSIST_STATE, + component = LOG_COMPONENT_SCANNER, + subsystem = LOG_SUBSYSTEM_RUNTIME, + state = "recovery_intent_startup_discovery_failed", + error = %error, + "Scanner recovery intent startup discovery failed" + ); + } if let Err(error) = resume_scanner_cycle_cleanup(ctx, storeapi).await { warn!( target: "rustfs::scanner", diff --git a/crates/scanner/src/scanner/tests/recovery_control.rs b/crates/scanner/src/scanner/tests/recovery_control.rs index 76ed49f4e..61ac96bc5 100644 --- a/crates/scanner/src/scanner/tests/recovery_control.rs +++ b/crates/scanner/src/scanner/tests/recovery_control.rs @@ -551,7 +551,7 @@ async fn scanner_recovery_intent_startup_rejects_corrupt_pending_record() { #[tokio::test] #[serial] -async fn scanner_recovery_intent_disabled_startup_preserves_non_terminal_intent() { +async fn scanner_recovery_intent_disabled_startup_replays_non_terminal_intent() { let (_dir, store) = setup_scanner_cycle_store().await; let record = match accept_scanner_usage_recovery_intent( store.clone(), @@ -567,12 +567,12 @@ async fn scanner_recovery_intent_disabled_startup_preserves_non_terminal_intent( let restarted = restart_scanner_cycle_store_from(&store).await; run_disabled_startup(CancellationToken::new(), restarted.clone()).await; - let preserved = get_scanner_usage_recovery_intent(restarted, &record.intent_id) + let completed = get_scanner_usage_recovery_intent(restarted, &record.intent_id) .await - .expect("startup-skipped intent should read") - .expect("startup-skipped intent should remain durable"); - assert_eq!(preserved.state, "accepted"); - assert_eq!(preserved.intent_id, record.intent_id); + .expect("startup-replayed intent should read") + .expect("startup-replayed intent should remain durable"); + assert_eq!(completed.state, "completed"); + assert_eq!(completed.intent_id, record.intent_id); } #[tokio::test]