Skip to content

Commit de72d1c

Browse files
authored
[web] retry safaridriver session creation (flutter#163791)
Speculatively retry when WebDriver session fails with a timed out Safari. It is hard enough to get `safaridriver` to open a local port, so one we have that going, it might be good to give a chance to connect to the browser 🤷 Fixes flutter#163790
1 parent e2c4ba3 commit de72d1c

File tree

1 file changed

+45
-10
lines changed

1 file changed

+45
-10
lines changed

engine/src/flutter/lib/web_ui/dev/safari_macos.dart

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import 'webdriver_browser.dart';
1515
/// Provides an environment for the desktop variant of Safari running on macOS.
1616
class SafariMacOsEnvironment extends BrowserEnvironment {
1717
static const Duration _waitBetweenRetries = Duration(seconds: 1);
18-
static const int _maxRetryCount = 5;
18+
static const int _maxRetryCount = 10;
1919

2020
late int _portNumber;
2121
late Process _driverProcess;
@@ -88,16 +88,9 @@ $stackTrace
8888

8989
await _waitForSafariDriverServerReady();
9090

91-
// Smoke-test the web driver process by connecting to it and asking for a
92-
// list of windows. It doesn't matter how many windows there are.
93-
webDriver = await createDriver(
94-
uri: _driverUri,
95-
desired: <String, dynamic>{'browserName': packageTestRuntime.identifier},
96-
);
97-
98-
await webDriver!.windows.toList();
91+
webDriver = await _createDriverSessionWithRetry();
9992
} catch (_) {
100-
print('safaridriver failed to start.');
93+
print('safaridriver failed to reach a healthy state.');
10194

10295
final badDriver = webDriver;
10396
webDriver = null; // let's not keep faulty driver around
@@ -141,6 +134,48 @@ $stackTrace
141134
}
142135
}
143136

137+
/// Creates a WebDriver session with a rety mechanism.
138+
///
139+
/// The retry mechanism is used to combat intermittent errors of the form:
140+
///
141+
/// > Could not create a session: The session timed out while connecting to a Safari instance.
142+
///
143+
/// See also: https://github.com/flutter/flutter/issues/163790
144+
Future<WebDriver> _createDriverSessionWithRetry() async {
145+
const kSessionRetryCount = 10;
146+
int retryCount = 0;
147+
while (true) {
148+
// Give Safari a chance to launch.
149+
//
150+
// 100ms seems enough in most cases, but feel free to revisit this.
151+
await Future<void>.delayed(const Duration(milliseconds: 100));
152+
153+
retryCount += 1;
154+
try {
155+
final candidateDriver = await createDriver(
156+
uri: _driverUri,
157+
desired: <String, dynamic>{'browserName': packageTestRuntime.identifier},
158+
);
159+
160+
// Smoke-test the web driver process by asking for a list of windows. It
161+
// doesn't matter how many windows there are, only that the driver is
162+
// capable of answering the question.
163+
await candidateDriver.windows.toList();
164+
165+
return candidateDriver;
166+
} catch (_) {
167+
if (retryCount < kSessionRetryCount) {
168+
print('Failed to create a WebDriver session with Safari. Retrying...');
169+
} else {
170+
print(
171+
'Failed to create a WebDriver session with Safari after $kSessionRetryCount retries. Giving up.',
172+
);
173+
rethrow;
174+
}
175+
}
176+
}
177+
}
178+
144179
/// The Safari Driver process cannot instantly spawn a server, so this function
145180
/// attempts to connect to the server in a loop until it succeeds.
146181
///

0 commit comments

Comments
 (0)