Skip to content

Commit 4946e86

Browse files
committed
Retry failed container removals (JVMHookResourceReaper)
Signed-off-by: Michael Edgar <medgar@redhat.com>
1 parent 990a7dc commit 4946e86

File tree

1 file changed

+62
-25
lines changed

1 file changed

+62
-25
lines changed
Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package org.testcontainers.utility;
22

3+
import com.github.dockerjava.api.DockerClient;
34
import com.github.dockerjava.api.model.Container;
45
import com.github.dockerjava.api.model.PruneType;
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
58

9+
import java.util.ArrayList;
610
import java.util.Arrays;
11+
import java.util.Collections;
712
import java.util.List;
813
import java.util.Map;
914

@@ -13,19 +18,34 @@
1318
*/
1419
class JVMHookResourceReaper extends ResourceReaper {
1520

21+
private static final Logger LOGGER = LoggerFactory.getLogger(JVMHookResourceReaper.class);
22+
1623
@Override
1724
public void init() {
1825
setHook();
1926
}
2027

28+
/**
29+
* Perform a cleanup.
30+
* @deprecated no longer supported API, use {@link DockerClient} directly
31+
*/
2132
@Override
33+
@Deprecated
2234
public synchronized void performCleanup() {
2335
super.performCleanup();
2436
synchronized (DEATH_NOTE) {
25-
DEATH_NOTE.forEach(filters -> prune(PruneType.CONTAINERS, filters));
26-
DEATH_NOTE.forEach(filters -> prune(PruneType.NETWORKS, filters));
27-
DEATH_NOTE.forEach(filters -> prune(PruneType.VOLUMES, filters));
28-
DEATH_NOTE.forEach(filters -> prune(PruneType.IMAGES, filters));
37+
tryPrune(PruneType.CONTAINERS);
38+
tryPrune(PruneType.NETWORKS);
39+
tryPrune(PruneType.VOLUMES);
40+
tryPrune(PruneType.IMAGES);
41+
}
42+
}
43+
44+
private void tryPrune(PruneType pruneType) {
45+
try {
46+
DEATH_NOTE.forEach(filters -> prune(pruneType, filters));
47+
} catch (Exception e) {
48+
LOGGER.warn("Exception pruning {} resources: {}", pruneType, e.getMessage(), e);
2949
}
3050
}
3151

@@ -35,28 +55,45 @@ private void prune(PruneType pruneType, List<Map.Entry<String, String>> filters)
3555
.filter(it -> "label".equals(it.getKey()))
3656
.map(Map.Entry::getValue)
3757
.toArray(String[]::new);
38-
switch (pruneType) {
58+
59+
if (pruneType == PruneType.CONTAINERS) {
3960
// Docker only prunes stopped containers, so we have to do it manually
40-
case CONTAINERS:
41-
List<Container> containers = dockerClient
42-
.listContainersCmd()
43-
.withFilter("label", Arrays.asList(labels))
44-
.withShowAll(true)
45-
.exec();
46-
47-
containers
48-
.parallelStream()
49-
.forEach(container -> {
50-
dockerClient
51-
.removeContainerCmd(container.getId())
52-
.withForce(true)
53-
.withRemoveVolumes(true)
54-
.exec();
55-
});
56-
break;
57-
default:
58-
dockerClient.pruneCmd(pruneType).withLabelFilter(labels).exec();
59-
break;
61+
removeContainers(labels);
62+
} else {
63+
dockerClient.pruneCmd(pruneType).withLabelFilter(labels).exec();
64+
}
65+
}
66+
67+
private void removeContainers(String[] labels) {
68+
List<Container> containers = listContainers(labels);
69+
int retries = 5;
70+
71+
while (!containers.isEmpty() && retries-- > 0) {
72+
List<Throwable> errors = new ArrayList<>();
73+
74+
containers.parallelStream().forEach(container -> removeContainer(container, errors));
75+
76+
if (errors.isEmpty()) {
77+
containers = Collections.emptyList();
78+
} else if (retries < 1) {
79+
RuntimeException removeError = new RuntimeException("Error removing one or more containers");
80+
errors.forEach(removeError::addSuppressed);
81+
throw removeError;
82+
} else {
83+
containers = listContainers(labels);
84+
}
85+
}
86+
}
87+
88+
private List<Container> listContainers(String[] labels) {
89+
return dockerClient.listContainersCmd().withFilter("label", Arrays.asList(labels)).withShowAll(true).exec();
90+
}
91+
92+
private void removeContainer(Container container, List<Throwable> errors) {
93+
try {
94+
dockerClient.removeContainerCmd(container.getId()).withForce(true).withRemoveVolumes(true).exec();
95+
} catch (Exception e) {
96+
errors.add(e);
6097
}
6198
}
6299
}

0 commit comments

Comments
 (0)