Skip to content

Commit a645b93

Browse files
berosonatebosch
andauthored
Async support for when, whenError and onRetry (#679)
Co-authored-by: Nate Bosch <[email protected]>
1 parent 1e42ffa commit a645b93

File tree

4 files changed

+50
-16
lines changed

4 files changed

+50
-16
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.13.5-dev
2+
3+
* Allow async callbacks in RetryClient.
4+
15
## 0.13.4
26

37
* Throw a more useful error when a client is used after it has been closed.

lib/retry.dart

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ class RetryClient extends BaseClient {
1818
final int _retries;
1919

2020
/// The callback that determines whether a request should be retried.
21-
final bool Function(BaseResponse) _when;
21+
final FutureOr<bool> Function(BaseResponse) _when;
2222

2323
/// The callback that determines whether a request when an error is thrown.
24-
final bool Function(Object, StackTrace) _whenError;
24+
final FutureOr<bool> Function(Object, StackTrace) _whenError;
2525

2626
/// The callback that determines how long to wait before retrying a request.
2727
final Duration Function(int) _delay;
2828

2929
/// The callback to call to indicate that a request is being retried.
30-
final void Function(BaseRequest, BaseResponse?, int)? _onRetry;
30+
final FutureOr<void> Function(BaseRequest, BaseResponse?, int)? _onRetry;
3131

3232
/// Creates a client wrapping [_inner] that retries HTTP requests.
3333
///
@@ -51,10 +51,11 @@ class RetryClient extends BaseClient {
5151
RetryClient(
5252
this._inner, {
5353
int retries = 3,
54-
bool Function(BaseResponse) when = _defaultWhen,
55-
bool Function(Object, StackTrace) whenError = _defaultWhenError,
54+
FutureOr<bool> Function(BaseResponse) when = _defaultWhen,
55+
FutureOr<bool> Function(Object, StackTrace) whenError = _defaultWhenError,
5656
Duration Function(int retryCount) delay = _defaultDelay,
57-
void Function(BaseRequest, BaseResponse?, int retryCount)? onRetry,
57+
FutureOr<void> Function(BaseRequest, BaseResponse?, int retryCount)?
58+
onRetry,
5859
}) : _retries = retries,
5960
_when = when,
6061
_whenError = whenError,
@@ -72,9 +73,10 @@ class RetryClient extends BaseClient {
7273
RetryClient.withDelays(
7374
Client inner,
7475
Iterable<Duration> delays, {
75-
bool Function(BaseResponse) when = _defaultWhen,
76-
bool Function(Object, StackTrace) whenError = _defaultWhenError,
77-
void Function(BaseRequest, BaseResponse?, int retryCount)? onRetry,
76+
FutureOr<bool> Function(BaseResponse) when = _defaultWhen,
77+
FutureOr<bool> Function(Object, StackTrace) whenError = _defaultWhenError,
78+
FutureOr<void> Function(BaseRequest, BaseResponse?, int retryCount)?
79+
onRetry,
7880
}) : this._withDelays(
7981
inner,
8082
delays.toList(),
@@ -86,9 +88,9 @@ class RetryClient extends BaseClient {
8688
RetryClient._withDelays(
8789
Client inner,
8890
List<Duration> delays, {
89-
required bool Function(BaseResponse) when,
90-
required bool Function(Object, StackTrace) whenError,
91-
required void Function(BaseRequest, BaseResponse?, int)? onRetry,
91+
required FutureOr<bool> Function(BaseResponse) when,
92+
required FutureOr<bool> Function(Object, StackTrace) whenError,
93+
required FutureOr<void> Function(BaseRequest, BaseResponse?, int)? onRetry,
9294
}) : this(
9395
inner,
9496
retries: delays.length,
@@ -108,19 +110,19 @@ class RetryClient extends BaseClient {
108110
try {
109111
response = await _inner.send(_copyRequest(request, splitter.split()));
110112
} catch (error, stackTrace) {
111-
if (i == _retries || !_whenError(error, stackTrace)) rethrow;
113+
if (i == _retries || !await _whenError(error, stackTrace)) rethrow;
112114
}
113115

114116
if (response != null) {
115-
if (i == _retries || !_when(response)) return response;
117+
if (i == _retries || !await _when(response)) return response;
116118

117119
// Make sure the response stream is listened to so that we don't leave
118120
// dangling connections.
119121
_unawaited(response.stream.listen((_) {}).cancel().catchError((_) {}));
120122
}
121123

122124
await Future<void>.delayed(_delay(i));
123-
_onRetry?.call(request, response, i);
125+
await _onRetry?.call(request, response, i);
124126
i++;
125127
}
126128
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: http
2-
version: 0.13.4
2+
version: 0.13.5-dev
33
homepage: https://github.com/dart-lang/http
44
description: A composable, multi-platform, Future-based API for HTTP requests.
55

test/http_retry_test.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,32 @@ void main() {
224224
final response = await client.send(request);
225225
expect(response.statusCode, equals(503));
226226
});
227+
228+
test('async when, whenError and onRetry', () async {
229+
final client = RetryClient(
230+
MockClient(expectAsync1(
231+
(request) async => request.headers['Authorization'] != null
232+
? Response('', 200)
233+
: Response('', 401),
234+
count: 2)),
235+
retries: 1,
236+
delay: (_) => Duration.zero,
237+
when: (response) async {
238+
await Future<void>.delayed(const Duration(milliseconds: 500));
239+
return response.statusCode == 401;
240+
},
241+
whenError: (error, stackTrace) async {
242+
await Future<void>.delayed(const Duration(milliseconds: 500));
243+
return false;
244+
},
245+
onRetry: (request, response, retryCount) async {
246+
expect(response?.statusCode, equals(401));
247+
await Future<void>.delayed(const Duration(milliseconds: 500));
248+
request.headers['Authorization'] = 'Bearer TOKEN';
249+
},
250+
);
251+
252+
final response = await client.get(Uri.http('example.org', ''));
253+
expect(response.statusCode, equals(200));
254+
});
227255
}

0 commit comments

Comments
 (0)