fix(notify): normalize lock ordering to prevent deadlock (#3199)

* fix(notify): normalize lock ordering to prevent deadlock

replace_targets() and shutdown() acquired target_list before replay_workers,
opposite to runtime_view.rs order. This is an ABBA deadlock pattern.

- Swap to replay_workers -> target_list order (canonical)
- Add lock order comments
- 82 notify tests pass

* docs(notify): update runtime facade lock order

* docs(notify): clarify runtime facade lock order

---------

Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
安正超
2026-06-03 23:37:59 +08:00
committed by GitHub
parent 1838922f07
commit a63aaf933d
2 changed files with 5 additions and 3 deletions
+1 -1
View File
@@ -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.
+4 -2
View File
@@ -81,8 +81,9 @@ impl NotifyRuntimeFacade {
}
pub async fn replace_targets(&self, activation: RuntimeActivation<Event>) -> 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)