From 0e535e710b5d6a286f76a7d5297d06be0465e550 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Tue, 2 Jun 2026 13:22:38 -0700 Subject: [PATCH] [vm_service] Fix socket exhaustion in resume_shutdown_race_test The resumer in `resume_shutdown_race_test.dart` was running in a tight `do-while` loop, hammering the VM server with `getVM` and `getIsolate` requests to check if all isolates are paused at exit. During VM shutdown, this rapid sequence of requests could cause socket exhaustion, especially on Windows, or trigger transient connection errors. This is fixed by adding a 10ms delay using `Future.delayed` at the end of each iteration, and wrapping the loop's HTTP request block in a `try-catch` block to gracefully log and ignore transient connection or request errors during VM shutdown. Change-Id: I1bfcad7505254a1feb59dfb654421547efc02d46 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/508720 Commit-Queue: Ben Konyi Reviewed-by: Mark Zhou Auto-Submit: Ben Konyi Commit-Queue: Mark Zhou --- .../test/resume_shutdown_race_test.dart | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/pkg/vm_service/test/resume_shutdown_race_test.dart b/pkg/vm_service/test/resume_shutdown_race_test.dart index 1f6addf720e..c5d057ea499 100644 --- a/pkg/vm_service/test/resume_shutdown_race_test.dart +++ b/pkg/vm_service/test/resume_shutdown_race_test.dart @@ -50,16 +50,25 @@ Future resumer(_) async { // Wait for the main isolate and children to all be paused at exit. final paused = []; do { - paused.clear(); - final vm = (await get('getVM', {}))['result']; - for (Map isolate in vm['isolates']) { - final id = isolate['id']; - isolate = (await get('getIsolate', {'isolateId': id}))['result']; - if ((isolate['pauseEvent'] != null) && - (isolate['pauseEvent']['kind'] == 'PauseExit')) { - paused.add(id); + try { + paused.clear(); + final vmResult = await get('getVM', {}); + final vm = vmResult['result']; + if (vm != null) { + for (Map isolate in vm['isolates']) { + final id = isolate['id']; + final isolateResult = await get('getIsolate', {'isolateId': id}); + isolate = isolateResult['result'] ?? {}; + if ((isolate['pauseEvent'] != null) && + (isolate['pauseEvent']['kind'] == 'PauseExit')) { + paused.add(id); + } + } } + } catch (e) { + print('Transient error in resumer: $e'); } + await Future.delayed(const Duration(milliseconds: 10)); } while (paused.length != childCount + 1); // Resume the main isolate and children. When the main isolate resumes, it