Skip to content

Commit 615530b

Browse files
authored
fix(core): remove race condition in shutdown state transition (#1088)
## Summary - Fix a race condition in `GracefulShutdownManager` where the monitor thread (with `initialDelay=0`) calls `updateTerminatedIfNoRequests()` on every tick, which can advance the state from `SHUTTING_DOWN` to `TERMINATED` before `performGracefulShutdown()` even returns. This causes `performShutdownTransition` test to fail flakily. - Move `updateTerminatedIfNoRequests()` from the monitor thread to two deterministic call sites: `unregisterRequest()` (when the last request completes) and `awaitTermination()` entry (for the "no active requests at shutdown time" edge case). ## Root Cause The monitor thread was responsible for both timeout enforcement (its intended job) and state transition (an overreach). Since it runs with `initialDelay=0`, it could execute `updateTerminatedIfNoRequests()` before `performGracefulShutdown()` returned to the caller, making the `SHUTTING_DOWN` state unobservable. ## Test plan - [x] `GracefulShutdownTest` (59 tests) all pass, including the previously flaky `performShutdownTransition` - [x] No other files changed, minimal blast radius Made with [Cursor](https://cursor.com)
1 parent 1fda297 commit 615530b

1 file changed

Lines changed: 2 additions & 3 deletions

File tree

agentscope-core/src/main/java/io/agentscope/core/shutdown/GracefulShutdownManager.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ public void unregisterRequest(Agent agent) {
167167
}
168168
activeRequestsByAgentId.remove(agent.getAgentId());
169169
sessionBindings.remove(agent.getAgentId());
170+
updateTerminatedIfNoRequests();
170171
}
171172

172173
private Optional<ActiveRequestContext> getActiveRequestByAgent(Agent agent) {
@@ -262,9 +263,6 @@ private void enforceTimeoutAndInterrupt() {
262263
}
263264
}
264265
}
265-
266-
// Always check if we can transition to TERMINATED (no active requests)
267-
updateTerminatedIfNoRequests();
268266
}
269267

270268
private void updateTerminatedIfNoRequests() {
@@ -284,6 +282,7 @@ private void updateTerminatedIfNoRequests() {
284282
* @return true if TERMINATED was reached, false if timed out
285283
*/
286284
public boolean awaitTermination(Duration timeout) {
285+
updateTerminatedIfNoRequests();
287286
long deadline =
288287
timeout != null ? System.currentTimeMillis() + timeout.toMillis() : Long.MAX_VALUE;
289288
synchronized (terminationLock) {

0 commit comments

Comments
 (0)