|
6 | 6 | import 'dart:async';
|
7 | 7 | import 'dart:convert';
|
8 | 8 | import 'dart:io';
|
| 9 | +import 'dart:math' as math; |
9 | 10 |
|
10 | 11 | import 'package:http/http.dart' as http;
|
| 12 | +import 'package:http_retry/http_retry.dart'; |
11 | 13 | import 'package:http_throttle/http_throttle.dart';
|
12 | 14 | import 'package:stack_trace/stack_trace.dart';
|
13 | 15 |
|
@@ -210,8 +212,40 @@ class _PubHttpClient extends http.BaseClient {
|
210 | 212 | /// The [_PubHttpClient] wrapped by [httpClient].
|
211 | 213 | final _pubClient = new _PubHttpClient();
|
212 | 214 |
|
| 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 | + |
213 | 219 | /// 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 | + })); |
215 | 249 |
|
216 | 250 | /// The underlying HTTP client wrapped by [httpClient].
|
217 | 251 | http.Client get innerHttpClient => _pubClient._inner;
|
|
0 commit comments