Skip to content

Commit

Permalink
Fix retry logic (#1762)
Browse files Browse the repository at this point in the history
Closes #1556
  • Loading branch information
kevmoo authored Dec 18, 2017
1 parent 35730f7 commit 667281e
Showing 1 changed file with 41 additions and 35 deletions.
76 changes: 41 additions & 35 deletions lib/src/http.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,39 +92,7 @@ class _PubHttpClient extends http.BaseClient {

_logResponse(streamedResponse);

var status = streamedResponse.statusCode;
// 401 responses should be handled by the OAuth2 client. It's very
// unlikely that they'll be returned by non-OAuth2 requests. We also want
// to pass along 400 responses from the token endpoint.
var tokenRequest = streamedResponse.request.url == oauth2.tokenEndpoint;
if (status < 400 || status == 401 || (status == 400 && tokenRequest)) {
return streamedResponse;
}

if (status == 406 &&
request.headers['Accept'] == PUB_API_HEADERS['Accept']) {
fail("Pub ${sdk.version} is incompatible with the current version of "
"${request.url.host}.\n"
"Upgrade pub to the latest version and try again.");
}

if (status == 500 &&
(request.url.host == "pub.dartlang.org" ||
request.url.host == "storage.googleapis.com")) {
var message = "HTTP error 500: Internal Server Error at "
"${request.url}.";

if (request.url.host == "pub.dartlang.org" ||
request.url.host == "storage.googleapis.com") {
message += "\nThis is likely a transient error. Please try again "
"later.";
}

fail(message);
}

throw new PubHttpException(
await http.Response.fromStream(streamedResponse));
return streamedResponse;
}

/// Whether extra metadata headers should be added to [request].
Expand Down Expand Up @@ -216,10 +184,48 @@ final _pubClient = new _PubHttpClient();
/// we're waiting for them to come back up.
final _retriedHosts = new Set<String>();

/// Intercepts all requests and throws exceptions if the response was not
/// considered successful.
class _ThrowingClient extends http.BaseClient {
final http.Client _inner;

_ThrowingClient(this._inner);

Future<http.StreamedResponse> send(http.BaseRequest request) async {
final streamedResponse = await _inner.send(request);

var status = streamedResponse.statusCode;
// 401 responses should be handled by the OAuth2 client. It's very
// unlikely that they'll be returned by non-OAuth2 requests. We also want
// to pass along 400 responses from the token endpoint.
var tokenRequest = streamedResponse.request.url == oauth2.tokenEndpoint;
if (status < 400 || status == 401 || (status == 400 && tokenRequest)) {
return streamedResponse;
}

if (status == 406 &&
request.headers['Accept'] == PUB_API_HEADERS['Accept']) {
fail("Pub ${sdk.version} is incompatible with the current version of "
"${request.url.host}.\n"
"Upgrade pub to the latest version and try again.");
}

if (status == 500 &&
(request.url.host == "pub.dartlang.org" ||
request.url.host == "storage.googleapis.com")) {
fail("HTTP error 500: Internal Server Error at ${request.url}.\n"
"This is likely a transient error. Please try again later.");
}

throw new PubHttpException(
await http.Response.fromStream(streamedResponse));
}
}

/// The HTTP client to use for all HTTP requests.
final httpClient = new ThrottleClient(
16,
new RetryClient(_pubClient,
new _ThrowingClient(new RetryClient(_pubClient,
retries: 5,
when: (response) => const [502, 503, 504].contains(response.statusCode),
delay: (retryCount) {
Expand All @@ -245,7 +251,7 @@ final httpClient = new ThrottleClient(
log.message(
"It looks like ${request.url.host} is having some trouble.\n"
"Pub will wait for a while before trying to connect again.");
}));
})));

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

0 comments on commit 667281e

Please sign in to comment.