@@ -21,19 +21,12 @@ import 'package:retry/retry.dart';
21
21
22
22
import 'configuration.dart' ;
23
23
import 'utils.dart'
24
- show
25
- contentType,
26
- jsonUtf8Encoder,
27
- retryAsync,
28
- ByteArrayEqualsExt,
29
- DeleteCounts;
24
+ show contentType, jsonUtf8Encoder, ByteArrayEqualsExt, DeleteCounts;
30
25
import 'versions.dart' as versions;
31
26
32
27
final _gzip = GZipCodec ();
33
28
final _logger = Logger ('shared.storage' );
34
29
35
- const _retryStatusCodes = < int > {502 , 503 , 504 };
36
-
37
30
/// Additional methods on the storage service.
38
31
extension StorageExt on Storage {
39
32
/// Verifies bucket existence and access.
@@ -115,18 +108,19 @@ extension BucketExt on Bucket {
115
108
}
116
109
117
110
/// Deletes [name] if it exists, ignores 404 otherwise.
118
- Future <void > tryDelete (String name) async {
119
- return await retry (
111
+ Future <bool > tryDeleteWithRetry (String name) async {
112
+ return await _retry (
120
113
() async {
121
114
try {
122
- return await delete (name);
115
+ await delete (name);
116
+ return true ;
123
117
} on DetailedApiRequestError catch (e) {
124
- if (e.status == 404 ) return null ;
118
+ if (e.status == 404 ) {
119
+ return false ;
120
+ }
125
121
rethrow ;
126
122
}
127
123
},
128
- maxAttempts: 3 ,
129
- retryIf: _retryIf,
130
124
);
131
125
}
132
126
@@ -158,7 +152,7 @@ extension BucketExt on Bucket {
158
152
if (maxSize != null && length != null && maxSize < length) {
159
153
throw MaximumSizeExceeded (maxSize);
160
154
}
161
- return retry (
155
+ return _retry (
162
156
() async {
163
157
final timeout = Duration (seconds: 30 );
164
158
final deadline = clock.now ().add (timeout);
@@ -175,8 +169,6 @@ extension BucketExt on Bucket {
175
169
}
176
170
return builder.toBytes ();
177
171
},
178
- maxAttempts: 3 ,
179
- retryIf: _retryIf,
180
172
);
181
173
}
182
174
@@ -270,8 +262,17 @@ extension PageExt<T> on Page<T> {
270
262
}
271
263
}
272
264
273
- Future <R > _retry <R >(Future <R > Function () fn) async {
274
- return await retry (fn, maxAttempts: 3 , retryIf: _retryIf);
265
+ Future <R > _retry <R >(
266
+ Future <R > Function () fn, {
267
+ FutureOr <void > Function (Exception )? onRetry,
268
+ }) async {
269
+ return await retry (
270
+ fn,
271
+ maxAttempts: 3 ,
272
+ delayFactor: Duration (seconds: 2 ),
273
+ retryIf: _retryIf,
274
+ onRetry: onRetry,
275
+ );
275
276
}
276
277
277
278
bool _retryIf (Exception e) {
@@ -295,32 +296,6 @@ bool _retryIf(Exception e) {
295
296
String bucketUri (Bucket bucket, String path) =>
296
297
'gs://${bucket .bucketName }/$path ' ;
297
298
298
- /// Deletes a single object from the [bucket] .
299
- ///
300
- /// Returns `true` if the object was deleted by this operation, `false` if it
301
- /// didn't exist at the time of the operation.
302
- Future <bool > deleteFromBucket (Bucket bucket, String objectName) async {
303
- Future <bool > delete () async {
304
- try {
305
- await bucket.delete (objectName);
306
- return true ;
307
- } on DetailedApiRequestError catch (e) {
308
- if (e.status != 404 ) {
309
- rethrow ;
310
- }
311
- return false ;
312
- }
313
- }
314
-
315
- return await retry (
316
- delete,
317
- delayFactor: Duration (seconds: 10 ),
318
- maxAttempts: 3 ,
319
- retryIf: (e) =>
320
- e is DetailedApiRequestError && _retryStatusCodes.contains (e.status),
321
- );
322
- }
323
-
324
299
Future <void > updateContentDispositionToAttachment (
325
300
ObjectInfo info, Bucket bucket) async {
326
301
if (info.metadata.contentDisposition != 'attachment' ) {
@@ -351,23 +326,19 @@ Future<int> deleteBucketFolderRecursively(
351
326
var count = 0 ;
352
327
Page <BucketEntry >? page;
353
328
while (page == null || ! page.isLast) {
354
- page = await retry (
329
+ page = await _retry (
355
330
() async {
356
331
return page == null
357
332
? await bucket.pageWithRetry (
358
333
prefix: folder, delimiter: '' , pageSize: 100 )
359
334
: await page.nextWithRetry (pageSize: 100 );
360
335
},
361
- delayFactor: Duration (seconds: 10 ),
362
- maxAttempts: 3 ,
363
- retryIf: (e) =>
364
- e is DetailedApiRequestError && _retryStatusCodes.contains (e.status),
365
336
);
366
337
final futures = < Future > [];
367
338
final pool = Pool (concurrency ?? 1 );
368
339
for (final entry in page! .items) {
369
340
final f = pool.withResource (() async {
370
- final deleted = await deleteFromBucket ( bucket, entry.name);
341
+ final deleted = await bucket. tryDeleteWithRetry ( entry.name);
371
342
if (deleted) count++ ;
372
343
});
373
344
futures.add (f);
@@ -382,7 +353,7 @@ Future<int> deleteBucketFolderRecursively(
382
353
Future uploadWithRetry (Bucket bucket, String objectName, int length,
383
354
Stream <List <int >> Function () openStream,
384
355
{ObjectMetadata ? metadata}) async {
385
- await retryAsync (
356
+ await _retry (
386
357
() async {
387
358
final sink = bucket.write (objectName,
388
359
length: length,
@@ -391,9 +362,9 @@ Future uploadWithRetry(Bucket bucket, String objectName, int length,
391
362
await sink.addStream (openStream ());
392
363
await sink.close ();
393
364
},
394
- description : 'Upload to $ objectName ' ,
395
- shouldRetryOnError : _retryIf,
396
- sleep : Duration (seconds : 10 ) ,
365
+ onRetry : (e) {
366
+ _logger. info ( 'Upload to $ objectName failed.' , e, StackTrace .current);
367
+ } ,
397
368
);
398
369
}
399
370
@@ -506,7 +477,7 @@ class VersionedJsonStorage {
506
477
final age = clock.now ().difference (info.updated);
507
478
if (minAgeThreshold == null || age > minAgeThreshold) {
508
479
deleted++ ;
509
- await deleteFromBucket ( _bucket, entry.name);
480
+ await _bucket. tryDeleteWithRetry ( entry.name);
510
481
}
511
482
}
512
483
});
0 commit comments