fix(peer): preserve monitor backoff per root
Track the last attempted configured root separately from the last successful snapshot. A root switch clears backoff once; repeated budget failures on that same root now retain exponential delay. Test Plan: - just test - just clippy - repeated failing-root backoff regression - git diff --check
This commit is contained in:
@@ -132,9 +132,18 @@ impl PollBudget {
|
|||||||
struct PollBackoff {
|
struct PollBackoff {
|
||||||
failures: u32,
|
failures: u32,
|
||||||
retry_at: Option<Instant>,
|
retry_at: Option<Instant>,
|
||||||
|
observed_root: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PollBackoff {
|
impl PollBackoff {
|
||||||
|
fn observe_root(&mut self, root: &Path) {
|
||||||
|
if self.observed_root.as_deref() == Some(root) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.observed_root = Some(root.to_path_buf());
|
||||||
|
self.record_success();
|
||||||
|
}
|
||||||
|
|
||||||
fn should_attempt(&self, now: Instant) -> bool {
|
fn should_attempt(&self, now: Instant) -> bool {
|
||||||
self.retry_at.is_none_or(|retry_at| now >= retry_at)
|
self.retry_at.is_none_or(|retry_at| now >= retry_at)
|
||||||
}
|
}
|
||||||
@@ -264,14 +273,8 @@ async fn poll_local_game_changes(
|
|||||||
previous: &mut Option<PollSnapshot>,
|
previous: &mut Option<PollSnapshot>,
|
||||||
backoff: &mut PollBackoff,
|
backoff: &mut PollBackoff,
|
||||||
) {
|
) {
|
||||||
let configured_game_dir = ctx.game_dir.read().await;
|
let configured_game_dir = ctx.game_dir.read().await.clone();
|
||||||
if previous
|
backoff.observe_root(&configured_game_dir);
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|snapshot| snapshot.game_dir != *configured_game_dir)
|
|
||||||
{
|
|
||||||
backoff.record_success();
|
|
||||||
}
|
|
||||||
drop(configured_game_dir);
|
|
||||||
|
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if !backoff.should_attempt(now) {
|
if !backoff.should_attempt(now) {
|
||||||
@@ -733,6 +736,27 @@ mod tests {
|
|||||||
assert_eq!(backoff.failures, 0);
|
assert_eq!(backoff.failures, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn root_change_resets_backoff_only_once_until_a_snapshot_succeeds() {
|
||||||
|
let now = Instant::now();
|
||||||
|
let mut backoff = PollBackoff::default();
|
||||||
|
let first_root = Path::new("/first");
|
||||||
|
let failing_root = Path::new("/oversized");
|
||||||
|
|
||||||
|
backoff.observe_root(first_root);
|
||||||
|
backoff.record_failure(now);
|
||||||
|
backoff.observe_root(failing_root);
|
||||||
|
assert!(backoff.should_attempt(now));
|
||||||
|
|
||||||
|
let delay = backoff.record_failure(now);
|
||||||
|
backoff.observe_root(failing_root);
|
||||||
|
assert!(
|
||||||
|
!backoff.should_attempt(now),
|
||||||
|
"re-observing the same failing root must preserve its backoff"
|
||||||
|
);
|
||||||
|
assert!(backoff.should_attempt(now + delay));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn snapshot_diff_detects_game_change_and_disappearance() {
|
fn snapshot_diff_detects_game_change_and_disappearance() {
|
||||||
let temp = TempDir::new("lanspread-local-monitor-change");
|
let temp = TempDir::new("lanspread-local-monitor-change");
|
||||||
|
|||||||
Reference in New Issue
Block a user