Skip to content

Commit 932e76e

Browse files
authored
Retry HTTP requests that are temporarily failing (#1759)
* Retry HTTP requests that are temporarily failing Closes #1556
1 parent 9f1e952 commit 932e76e

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

lib/src/http.dart

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
import 'dart:async';
77
import 'dart:convert';
88
import 'dart:io';
9+
import 'dart:math' as math;
910

1011
import 'package:http/http.dart' as http;
12+
import 'package:http_retry/http_retry.dart';
1113
import 'package:http_throttle/http_throttle.dart';
1214
import 'package:stack_trace/stack_trace.dart';
1315

@@ -210,8 +212,40 @@ class _PubHttpClient extends http.BaseClient {
210212
/// The [_PubHttpClient] wrapped by [httpClient].
211213
final _pubClient = new _PubHttpClient();
212214

215+
/// A set of all hostnames for which we've printed a message indicating that
216+
/// we're waiting for them to come back up.
217+
final _retriedHosts = new Set<String>();
218+
213219
/// The HTTP client to use for all HTTP requests.
214-
final httpClient = new ThrottleClient(16, _pubClient);
220+
final httpClient = new ThrottleClient(
221+
16,
222+
new RetryClient(_pubClient,
223+
retries: 5,
224+
when: (response) => const [502, 503, 504].contains(response.statusCode),
225+
delay: (retryCount) {
226+
if (retryCount < 3) {
227+
// Retry quickly a couple times in case of a short transient error.
228+
//
229+
// Add a random delay to avoid retrying a bunch of parallel requests
230+
// all at the same time.
231+
return new Duration(milliseconds: 500) * math.pow(1.5, retryCount) +
232+
new Duration(milliseconds: random.nextInt(500));
233+
} else {
234+
// If the error persists, wait a long time. This works around issues
235+
// where an AppEngine instance will go down and need to be rebooted,
236+
// which takes about a minute.
237+
return new Duration(seconds: 30);
238+
}
239+
},
240+
onRetry: (request, response, retryCount) {
241+
log.io("Retry #${retryCount + 1} for "
242+
"${request.method} ${request.url}...");
243+
if (retryCount != 3) return;
244+
if (!_retriedHosts.add(request.url.host)) return;
245+
log.message(
246+
"It looks like ${request.url.host} is having some trouble.\n"
247+
"Pub will wait for a while before trying to connect again.");
248+
}));
215249

216250
/// The underlying HTTP client wrapped by [httpClient].
217251
http.Client get innerHttpClient => _pubClient._inner;

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ dependencies:
1515
glob: "^1.0.0"
1616
http: "^0.11.0"
1717
http_multi_server: ">=1.0.0 <3.0.0"
18+
http_retry: "^0.1.0"
1819
http_throttle: "^1.0.0"
1920
json_rpc_2: "^2.0.0"
2021
meta: "^1.1.0"

0 commit comments

Comments
 (0)