Unverified Commit ad540e4f authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] retry chrome launch up to 3 times (#85162)

parent e67113c1
...@@ -249,7 +249,9 @@ class ChromiumLauncher { ...@@ -249,7 +249,9 @@ class ChromiumLauncher {
// Keep attempting to launch the browser until one of: // Keep attempting to launch the browser until one of:
// - Chrome launched successfully, in which case we just return from the loop. // - Chrome launched successfully, in which case we just return from the loop.
// - The tool detected an unretriable Chrome error, in which case we throw ToolExit. // - The tool reached the maximum retry count, in which case we throw ToolExit.
const int kMaxRetries = 3;
int retry = 0;
while (true) { while (true) {
final Process process = await _processManager.start(args); final Process process = await _processManager.start(args);
...@@ -263,6 +265,7 @@ class ChromiumLauncher { ...@@ -263,6 +265,7 @@ class ChromiumLauncher {
// Wait until the DevTools are listening before trying to connect. This is // Wait until the DevTools are listening before trying to connect. This is
// only required for flutter_test --platform=chrome and not flutter run. // only required for flutter_test --platform=chrome and not flutter run.
bool hitGlibcBug = false; bool hitGlibcBug = false;
bool shouldRetry = false;
await process.stderr await process.stderr
.transform(utf8.decoder) .transform(utf8.decoder)
.transform(const LineSplitter()) .transform(const LineSplitter())
...@@ -270,6 +273,7 @@ class ChromiumLauncher { ...@@ -270,6 +273,7 @@ class ChromiumLauncher {
_logger.printTrace('[CHROME]:$line'); _logger.printTrace('[CHROME]:$line');
if (line.contains(_kGlibcError)) { if (line.contains(_kGlibcError)) {
hitGlibcBug = true; hitGlibcBug = true;
shouldRetry = true;
} }
return line; return line;
}) })
...@@ -282,17 +286,22 @@ class ChromiumLauncher { ...@@ -282,17 +286,22 @@ class ChromiumLauncher {
// Return value unused. // Return value unused.
return ''; return '';
} }
_logger.printTrace('Failed to launch browser. Command used to launch it: ${args.join(' ')}'); if (retry >= kMaxRetries) {
_logger.printTrace('Failed to launch browser after $kMaxRetries tries. Command used to launch it: ${args.join(' ')}');
throw ToolExit( throw ToolExit(
'Failed to launch browser. Make sure you are using an up-to-date ' 'Failed to launch browser. Make sure you are using an up-to-date '
'Chrome or Edge. Otherwise, consider using -d web-server instead ' 'Chrome or Edge. Otherwise, consider using -d web-server instead '
'and filing an issue at https://github.com/flutter/flutter/issues.', 'and filing an issue at https://github.com/flutter/flutter/issues.',
); );
}
shouldRetry = true;
return '';
}); });
if (!hitGlibcBug) { if (!hitGlibcBug && !shouldRetry) {
return process; return process;
} }
retry += 1;
// A precaution that avoids accumulating browser processes, in case the // A precaution that avoids accumulating browser processes, in case the
// glibc bug doesn't cause the browser to quit and we keep looping and // glibc bug doesn't cause the browser to quit and we keep looping and
......
...@@ -461,7 +461,45 @@ void main() { ...@@ -461,7 +461,45 @@ void main() {
); );
}); });
testWithoutContext('gives up retrying when a non-glibc error happens', () async { testWithoutContext('can retry launch when chrome fails to start', () async {
const List<String> args = <String>[
'example_chrome',
'--user-data-dir=/.tmp_rand0/flutter_tools_chrome_device.rand0',
'--remote-debugging-port=12345',
...kChromeArgs,
'--headless',
'--disable-gpu',
'--no-sandbox',
'--window-size=2400,1800',
'example_url',
];
// Pretend to random error 3 times.
for (int i = 0; i < 3; i++) {
processManager.addCommand(const FakeCommand(
command: args,
stderr: 'BLAH BLAH',
));
}
// Succeed on the 4th try.
processManager.addCommand(const FakeCommand(
command: args,
stderr: kDevtoolsStderr,
));
expect(
() async => chromeLauncher.launch(
'example_url',
skipCheck: true,
headless: true,
),
returnsNormally,
);
});
testWithoutContext('gives up retrying when an error happens more than 3 times', () async {
for (int i = 0; i < 4; i++) {
processManager.addCommand(const FakeCommand( processManager.addCommand(const FakeCommand(
command: <String>[ command: <String>[
'example_chrome', 'example_chrome',
...@@ -476,6 +514,7 @@ void main() { ...@@ -476,6 +514,7 @@ void main() {
], ],
stderr: 'nothing in the std error indicating glibc error', stderr: 'nothing in the std error indicating glibc error',
)); ));
}
expect( expect(
() async => chromeLauncher.launch( () async => chromeLauncher.launch(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment