fix(scanner): preserve explicit cycle retry cadence (#7107)

Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
Henry Guo
2026-09-03 22:30:46 +08:00
committed by GitHub
parent 8a8616b8f7
commit 3a914b429d
3 changed files with 51 additions and 1 deletions
+1 -1
View File
@@ -2895,7 +2895,7 @@ where
);
let mut wait_plan =
scanner_cycle_wait_plan(&runtime_config, clean_idle_backoff, backoff_enabled, randomized_cycle_delay_for);
let superseded_retry_interval = superseded_backoff.retry_interval(runtime_config.cycle_interval);
let superseded_retry_interval = scanner_superseded_retry_interval(superseded_backoff, &runtime_config);
let deferred_retry_interval = deferred_backoff.retry_interval(runtime_config.cycle_interval);
let mut convergence_retry_interval = superseded_retry_interval.or(deferred_retry_interval);
if let Some(retry_interval) = convergence_retry_interval {
+16
View File
@@ -109,6 +109,22 @@ impl ScannerRetryBackoff {
}
}
pub(super) fn scanner_superseded_retry_interval(
backoff: ScannerRetryBackoff,
runtime_config: &ScannerRuntimeConfig,
) -> Option<Duration> {
let retry_interval = backoff.retry_interval(runtime_config.cycle_interval)?;
if runtime_config.cycle_interval_source == ScannerRuntimeConfigSource::Default {
return Some(retry_interval);
}
// An explicit cycle is an operator-selected duty-cycle floor. A
// superseded snapshot keeps its dirty work pending, but retrying that work
// sooner than the configured cadence would turn continuous writes into a
// repeated full-walk loop despite the override.
Some(retry_interval.max(runtime_config.cycle_interval))
}
const SCANNER_PUBLICATION_PROOF_RETRY_MAX_INTERVAL: Duration = Duration::from_secs(30);
pub(crate) fn scanner_publication_proof_retry_delay(consecutive_failures: u32) -> Duration {
+34
View File
@@ -7197,6 +7197,40 @@ fn superseded_retry_backoff_grows_from_the_default_cycle() {
}
}
#[test]
fn superseded_retry_preserves_explicit_cycle_cadence() {
let mut backoff = ScannerRetryBackoff::default();
backoff.record_retryable_cycle(true);
let default_config = ScannerRuntimeConfig {
cycle_interval: Duration::from_secs(6 * 60 * 60),
..Default::default()
};
assert_eq!(
scanner_superseded_retry_interval(backoff, &default_config),
Some(SCANNER_RETRY_BASE_INTERVAL),
"the default adaptive cadence must retain fast convergence"
);
for source in [
ScannerRuntimeConfigSource::Env,
ScannerRuntimeConfigSource::Config,
ScannerRuntimeConfigSource::ScannerCompatConfig,
] {
let runtime_config = ScannerRuntimeConfig {
cycle_interval: Duration::from_secs(6 * 60 * 60),
cycle_interval_source: source,
..Default::default()
};
assert_eq!(
scanner_superseded_retry_interval(backoff, &runtime_config),
Some(runtime_config.cycle_interval),
"{source:?} cycle cadence must not be shortened by convergence retries"
);
}
}
#[test]
fn publication_proof_retry_backoff_reaches_its_short_cap() {
for (failures, expected) in [(1, 5), (2, 10), (3, 20), (4, 30), (20, 30)] {