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
+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)