Skip to content

Commit 490edb3

Browse files
committed
Clear placement reconcile flag via Drop guard
placement_reconcile_in_flight is set with a CAS at the top of schedule_machine_placement_reconcile and was cleared by an explicit store at the end of the spawned thread. If reconcile_machine_placements ever panicked, the explicit store would not run and the flag would latch forever, silently disabling every future reconcile for the lifetime of the process. Wrap the cleared-on-completion behaviour in a PlacementReconcileGuard whose Drop impl clears the AtomicBool. Construct the guard on the calling thread before thread::spawn so the flag also clears if the spawn itself fails. The reconcile thread now drops the guard on return or unwind, so any future panic in reconcile_machine_placements no longer wedges the control plane.
1 parent 2650b9b commit 490edb3

1 file changed

Lines changed: 25 additions & 7 deletions

File tree

crates/port-runtime/src/hosted_control_plane.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4689,6 +4689,21 @@ fn schedule_machine_placement_reconcile(
46894689
});
46904690
}
46914691

4692+
#[cfg(not(test))]
4693+
struct PlacementReconcileGuard {
4694+
state: ControlPlaneState,
4695+
}
4696+
4697+
#[cfg(not(test))]
4698+
impl Drop for PlacementReconcileGuard {
4699+
fn drop(&mut self) {
4700+
self.state
4701+
.inner
4702+
.placement_reconcile_in_flight
4703+
.store(false, std::sync::atomic::Ordering::Release);
4704+
}
4705+
}
4706+
46924707
#[cfg(not(test))]
46934708
fn schedule_machine_placement_reconcile(
46944709
state: &ControlPlaneState,
@@ -4708,20 +4723,23 @@ fn schedule_machine_placement_reconcile(
47084723
return;
47094724
}
47104725

4711-
let state = state.clone();
4726+
// Construct the guard before the thread::spawn so the in-flight
4727+
// flag clears via Drop even if reconcile_machine_placements panics
4728+
// or thread::spawn itself fails. Without this, a single panic
4729+
// would latch the flag forever and silently disable every future
4730+
// reconcile for the lifetime of the process.
4731+
let guard = PlacementReconcileGuard {
4732+
state: state.clone(),
4733+
};
47124734
thread::spawn(move || {
4713-
if let Err(error) = reconcile_machine_placements(&state, &trigger) {
4735+
if let Err(error) = reconcile_machine_placements(&guard.state, &trigger) {
47144736
eprintln!(
47154737
"control plane '{}' placement reconcile triggered by {} failed: {}",
4716-
state.inner.control_plane,
4738+
guard.state.inner.control_plane,
47174739
trigger.detail(),
47184740
error
47194741
);
47204742
}
4721-
state
4722-
.inner
4723-
.placement_reconcile_in_flight
4724-
.store(false, std::sync::atomic::Ordering::Release);
47254743
});
47264744
}
47274745

0 commit comments

Comments
 (0)