Skip to content

Commit 63242f0

Browse files
fix: retry transient per-object delete failures in removeObjects() cleanup (#1700)
Co-authored-by: Bala FA <bala.gluster@gmail.com>
1 parent a34e8c4 commit 63242f0

1 file changed

Lines changed: 48 additions & 10 deletions

File tree

functional/TestMinioClient.java

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
import io.minio.messages.AccessControlPolicy;
9393
import io.minio.messages.CORSConfiguration;
9494
import io.minio.messages.DeleteRequest;
95+
import io.minio.messages.DeleteResult;
9596
import io.minio.messages.ErrorResponse;
9697
import io.minio.messages.EventType;
9798
import io.minio.messages.Filter;
@@ -121,8 +122,10 @@
121122
import java.util.Arrays;
122123
import java.util.Collections;
123124
import java.util.HashMap;
125+
import java.util.HashSet;
124126
import java.util.List;
125127
import java.util.Map;
128+
import java.util.Set;
126129
import java.util.concurrent.TimeUnit;
127130
import java.util.stream.Collectors;
128131
import okhttp3.Headers;
@@ -136,6 +139,12 @@
136139
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
137140
value = {"THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION", "REC_CATCH_EXCEPTION"})
138141
public class TestMinioClient extends TestArgs {
142+
private static final int MAX_DELETE_ATTEMPTS = 5;
143+
private static final Set<String> TRANSIENT_DELETE_CODES =
144+
Collections.unmodifiableSet(
145+
new HashSet<>(
146+
Arrays.asList("InternalError", "RequestTimeout", "ServiceUnavailable", "SlowDown")));
147+
139148
private String bucketName = getRandomName();
140149
private String bucketNameWithLock = getRandomName();
141150
public boolean isQuickTest;
@@ -1029,15 +1038,46 @@ public List<ObjectWriteResponse> createObjects(String bucketName, int count, int
10291038
public void removeObjects(String bucketName, List<ObjectWriteResponse> results) throws Exception {
10301039
List<DeleteRequest.Object> objects =
10311040
results.stream()
1032-
.map(
1033-
result -> {
1034-
return new DeleteRequest.Object(result.object(), result.versionId());
1035-
})
1041+
.map(r -> new DeleteRequest.Object(r.object(), r.versionId()))
10361042
.collect(Collectors.toList());
1037-
for (Result<?> r :
1038-
client.removeObjects(
1039-
RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build())) {
1040-
ignore(r.get());
1043+
boolean anyTransient = false;
1044+
for (int attempt = 0; attempt < MAX_DELETE_ATTEMPTS; attempt++) {
1045+
if (attempt > 0) {
1046+
try {
1047+
Thread.sleep(500L << attempt); // 1s / 2s / 4s / 8s
1048+
} catch (InterruptedException ie) {
1049+
Thread.currentThread().interrupt();
1050+
throw ie;
1051+
}
1052+
}
1053+
anyTransient = false;
1054+
for (Result<DeleteResult.Error> r :
1055+
client.removeObjects(
1056+
RemoveObjectsArgs.builder().bucket(bucketName).objects(objects).build())) {
1057+
DeleteResult.Error err = r.get();
1058+
String code = err.code();
1059+
if (!TRANSIENT_DELETE_CODES.contains(code)) {
1060+
throw new Exception(
1061+
"non-transient delete error '"
1062+
+ code
1063+
+ "': "
1064+
+ err.message()
1065+
+ " on "
1066+
+ err.objectName()
1067+
+ " in bucket "
1068+
+ bucketName);
1069+
}
1070+
anyTransient = true;
1071+
}
1072+
if (!anyTransient) break;
1073+
}
1074+
if (anyTransient) {
1075+
throw new Exception(
1076+
results.size()
1077+
+ " object(s) not deleted after "
1078+
+ MAX_DELETE_ATTEMPTS
1079+
+ " attempts in bucket "
1080+
+ bucketName);
10411081
}
10421082
}
10431083

@@ -1190,8 +1230,6 @@ public void testRemoveObjects(String testTags, List<ObjectWriteResponse> results
11901230
mintSuccessLog(methodName, testTags, startTime);
11911231
} catch (Exception e) {
11921232
handleException(methodName, testTags, startTime, e);
1193-
} finally {
1194-
removeObjects(bucketName, results);
11951233
}
11961234
}
11971235

0 commit comments

Comments
 (0)