Fix app-server thread listener startup and shutdown races (#57787)

## Why

A thread runtime can shut down while listener setup is awaiting I/O, and a cold resume can start before the previous listener forwards `ShutdownComplete`. Listener replacement must preserve those buffered terminal events.

## What changed

- Coordinate listener installation and connection subscriptions with pending unloads, and reject closing or replaced runtimes.
- Allow a newly created runtime that has already shut down to drain its queued events, while enforcing one event reader per runtime.
- Track shutdown draining with a shared watch channel so cold resume and runtime replacement wait for terminal events to be processed.
- Serialize idle unloading with goal edits and cold resume, and recheck thread state after acquiring the lock.

GitOrigin-RevId: d05e348b0a81bddb2defa963d0cfd3fde08dbd03
This commit is contained in:
Charlie Marsh
2026-10-28 16:53:55 +00:00
committed by copyberry
parent c8bd6c1da9
commit 575cc5351e
10 changed files with 541 additions and 322 deletions
+9 -1
View File
@@ -866,8 +866,16 @@ impl MessageProcessor {
thread_id: ThreadId,
connection_ids: Vec<ConnectionId>,
) {
let Ok(thread) = self
.thread_processor
.thread_manager
.get_thread(thread_id)
.await
else {
return;
};
self.thread_processor
.try_attach_thread_listener(thread_id, connection_ids)
.try_attach_thread_listener(thread_id, thread, connection_ids)
.await;
}