Unverified Commit 50a9c31f authored by Devon Carew's avatar Devon Carew Committed by GitHub

reduce retry attempts for flutter creatte --list-samples (#32833)

parent bfae0bb5
......@@ -14,18 +14,23 @@ const int kNetworkProblemExitCode = 50;
typedef HttpClientFactory = HttpClient Function();
/// Download a file from the given URL and return the bytes.
Future<List<int>> fetchUrl(Uri url) async {
Future<List<int>> fetchUrl(Uri url, {int maxAttempts}) async {
int attempts = 0;
int duration = 1;
int durationSeconds = 1;
while (true) {
attempts += 1;
final List<int> result = await _attempt(url);
if (result != null)
return result;
printStatus('Download failed -- attempting retry $attempts in $duration second${ duration == 1 ? "" : "s"}...');
await Future<void>.delayed(Duration(seconds: duration));
if (duration < 64)
duration *= 2;
if (maxAttempts != null && attempts >= maxAttempts) {
printStatus('Download failed -- retry $attempts');
return null;
}
printStatus('Download failed -- attempting retry $attempts in '
'$durationSeconds second${ durationSeconds == 1 ? "" : "s"}...');
await Future<void>.delayed(Duration(seconds: durationSeconds));
if (durationSeconds < 64)
durationSeconds *= 2;
}
}
......
......@@ -203,7 +203,8 @@ class CreateCommand extends FlutterCommand {
/// Fetches the samples index file from the Flutter docs website.
Future<String> _fetchSamplesIndexFromServer() async {
return utf8.decode(await fetchUrl(Uri.https(_snippetsHost, 'snippets/index.json')));
return utf8.decode(
await fetchUrl(Uri.https(_snippetsHost, 'snippets/index.json'), maxAttempts: 2));
}
/// Fetches the samples index file from the server and writes it to
......@@ -214,8 +215,14 @@ class CreateCommand extends FlutterCommand {
if (outputFile.existsSync()) {
throwToolExit('File "$outputFilePath" already exists', exitCode: 1);
}
outputFile.writeAsStringSync(await _fetchSamplesIndexFromServer());
printStatus('Wrote samples JSON to "$outputFilePath"');
final String samplesJson = await _fetchSamplesIndexFromServer();
if (samplesJson == null) {
throwToolExit('Unable to download samples', exitCode: 2);
}
else {
outputFile.writeAsStringSync(samplesJson);
printStatus('Wrote samples JSON to "$outputFilePath"');
}
} catch (e) {
throwToolExit('Failed to write samples JSON to "$outputFilePath": $e', exitCode: 2);
}
......@@ -224,6 +231,9 @@ class CreateCommand extends FlutterCommand {
@override
Future<FlutterCommandResult> runCommand() async {
if (argResults['list-samples'] != null) {
// _writeSamplesJson can potentially be long-lived.
Cache.releaseLockEarly();
await _writeSamplesJson(argResults['list-samples']);
return null;
}
......
......@@ -104,6 +104,30 @@ void main() {
),
});
testUsingContext('max attempts', () async {
String error;
List<int> actualResult;
FakeAsync().run((FakeAsync time) {
fetchUrl(Uri.parse('http://example.invalid/'), maxAttempts: 3).then((List<int> value) {
actualResult = value;
}, onError: (dynamic exception) {
error = 'test failed unexpectedly: $exception';
});
expect(testLogger.statusText, '');
time.elapse(const Duration(milliseconds: 10000));
expect(testLogger.statusText,
'Download failed -- attempting retry 1 in 1 second...\n'
'Download failed -- attempting retry 2 in 2 seconds...\n'
'Download failed -- retry 3\n',
);
});
expect(testLogger.errorText, isEmpty);
expect(error, isNull);
expect(actualResult, isNull);
}, overrides: <Type, Generator>{
HttpClientFactory: () => () => MockHttpClient(500),
});
testUsingContext('remote file non-existant', () async {
final Uri invalid = Uri.parse('http://example.invalid/');
final bool result = await doesRemoteFileExist(invalid);
......
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