diff --git a/crates/notify/AGENTS.md b/crates/notify/AGENTS.md index 7a7acb738..04d996a90 100644 --- a/crates/notify/AGENTS.md +++ b/crates/notify/AGENTS.md @@ -31,7 +31,7 @@ shared plugin/runtime primitives from `rustfs-targets`. ## Concurrency - `runtime_view.rs` acquires locks in order: `stream_cancellers` → `target_list`. -- `runtime_facade.rs` acquires locks in order: `target_list` → `replay_workers`. +- `runtime_facade.rs` acquires locks in order: `replay_workers` → `target_list`. - These orders must not be reversed in new code. When adding a function that needs both `target_list` and `stream_cancellers`, acquire `stream_cancellers` first (matching `runtime_view.rs` order). - Do not hold write guards across `.await` points unless the hold time is bounded and the operation is unavoidably async. diff --git a/crates/notify/src/runtime_facade.rs b/crates/notify/src/runtime_facade.rs index 1507f7f66..1c6bd655d 100644 --- a/crates/notify/src/runtime_facade.rs +++ b/crates/notify/src/runtime_facade.rs @@ -81,8 +81,9 @@ impl NotifyRuntimeFacade { } pub async fn replace_targets(&self, activation: RuntimeActivation) -> Result<(), NotificationError> { - let mut target_list = self.target_list.write().await; + // Lock order: replay_workers -> target_list (matches notify AGENTS.md). let mut replay_workers = self.replay_workers.write().await; + let mut target_list = self.target_list.write().await; self.runtime_adapter .replace_runtime_targets(target_list.runtime_mut(), &mut replay_workers, activation) .await @@ -102,8 +103,9 @@ impl NotifyRuntimeFacade { info!("Stops {} active event stream processing tasks", active_targets); { - let mut target_list = self.target_list.write().await; + // Lock order: replay_workers -> target_list (matches notify AGENTS.md). let mut replay_workers = self.replay_workers.write().await; + let mut target_list = self.target_list.write().await; if let Err(err) = self .runtime_adapter .shutdown(target_list.runtime_mut(), &mut replay_workers)