Skip to content

Commit 829910f

Browse files
mkustermanncommit-bot@chromium.org
authored andcommitted
Rate limit the number of gsutil.py subprocesses tools/approve_results.dart spawns
Without any rate limiting, the `tools/approve_results.dart` tool can render a machine unusable (e.g. when running with `tools/approve_results.dart -b '*'`). Unfortunately each gsutil.py subprocess might launch many more subprocesses on it's own due to us passing the '-m' flag. Change-Id: I06f4f54fb87a107d83d34205dafe03a8c73d747d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106902 Reviewed-by: Jonas Termansen <sortie@google.com> Auto-Submit: Martin Kustermann <kustermann@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com>
1 parent effb303 commit 829910f

1 file changed

Lines changed: 29 additions & 20 deletions

File tree

tools/bots/results.dart

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
import 'dart:async';
88
import 'dart:convert';
99
import 'dart:io';
10+
import 'dart:math';
11+
12+
import 'package:pool/pool.dart';
1013

1114
/// The path to the gsutil script.
1215
String gsutilPy;
@@ -18,30 +21,36 @@ const testResultsStoragePath = "gs://dart-test-results/builders";
1821
const approvedResultsStoragePath =
1922
"gs://dart-test-results-approved-results/builders";
2023

24+
/// Limit the number of concurrent subprocesses by half the number of cores.
25+
final gsutilPool = new Pool(max(1, Platform.numberOfProcessors ~/ 2));
26+
2127
/// Runs gsutil with the provided [arguments] and returns the standard output.
2228
/// Returns null if the requested URL didn't exist.
2329
Future<String> runGsutil(List<String> arguments) async {
24-
final processResult = await Process.run(
25-
"python", [gsutilPy]..addAll(arguments),
26-
runInShell: Platform.isWindows);
27-
if (processResult.exitCode != 0) {
28-
if (processResult.exitCode == 1 &&
29-
processResult.stderr.contains("No URLs matched") ||
30-
processResult.stderr.contains("One or more URLs matched no objects")) {
31-
return null;
32-
}
33-
String error = "Failed to run: python $gsutilPy $arguments\n"
34-
"exitCode: ${processResult.exitCode}\n"
35-
"stdout:\n${processResult.stdout}\n"
36-
"stderr:\n${processResult.stderr}";
37-
if (processResult.exitCode == 1 &&
38-
processResult.stderr.contains("401 Anonymous caller")) {
39-
error =
40-
"\n\nYou need to authenticate by running:\npython $gsutilPy config\n";
30+
return gsutilPool.withResource(() async {
31+
final processResult = await Process.run(
32+
"python", [gsutilPy]..addAll(arguments),
33+
runInShell: Platform.isWindows);
34+
if (processResult.exitCode != 0) {
35+
if (processResult.exitCode == 1 &&
36+
processResult.stderr.contains("No URLs matched") ||
37+
processResult.stderr
38+
.contains("One or more URLs matched no objects")) {
39+
return null;
40+
}
41+
String error = "Failed to run: python $gsutilPy $arguments\n"
42+
"exitCode: ${processResult.exitCode}\n"
43+
"stdout:\n${processResult.stdout}\n"
44+
"stderr:\n${processResult.stderr}";
45+
if (processResult.exitCode == 1 &&
46+
processResult.stderr.contains("401 Anonymous caller")) {
47+
error =
48+
"\n\nYou need to authenticate by running:\npython $gsutilPy config\n";
49+
}
50+
throw new Exception(error);
4151
}
42-
throw new Exception(error);
43-
}
44-
return processResult.stdout;
52+
return processResult.stdout;
53+
});
4554
}
4655

4756
/// Returns the contents of the provided cloud storage [path], or null if it

0 commit comments

Comments
 (0)