testcontainers / testcontainers/testcontainers-java
ConcurrentModificationException using new Startable.dependsOn(startable)
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 8.7k
- Forks
- 1.9k
- Avg merge
- 2d 17h
- Merged PRs (30d)
- 9
Description
I ran into an error in one of my TravisCI builds using the new dependsOn mechanism:
13780 ERROR 🐳 [postgres:9.6.12] - Could not start container
java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1660)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:550)
at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:517)
at org.testcontainers.containers.GenericContainer.applyConfiguration(GenericContainer.java:510)
at org.testcontainers.containers.GenericContainer.tryStart(GenericContainer.java:301)
at org.testcontainers.containers.GenericContainer.lambda$doStart$0(GenericContainer.java:285)
at org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess(Unreliables.java:81)
at org.testcontainers.containers.GenericContainer.doStart(GenericContainer.java:283)
at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:272)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
My containers are defined like this:
@Container
public static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>()
.withNetworkAliases("testpostgres")
.withDatabaseName("testdb");
@Container
public static MicroProfileApplication<?> app = new MicroProfileApplication<>()
.withEnv("POSTGRES_HOSTNAME", "testpostgres")
.withEnv("POSTGRES_PORT", "5432")
.withAppContextRoot("/myservice")
.dependsOn(postgres);
Using the latest version of testcontainers (1.12.0), the exception lines up with this bit of code:
private void applyConfiguration(CreateContainerCmd createCommand) {
HostConfig hostConfig = buildHostConfig();
createCommand.withHostConfig(hostConfig);
// Set up exposed ports (where there are no host port bindings defined)
ExposedPort[] portArray = exposedPorts.stream()
.map(ExposedPort::new)
.toArray(ExposedPort[]::new); // << --- CONCURRENT MOD EX HERE
It should also be noted that I am starting my containers in parallel like this:
containersToStart.parallelStream().forEach(GenericContainer::start);
which should be OK, since I believe the main value of dependsOn is that it allows us to do parallel container start without needing to worry about dependencies.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in GenericContainer.applyConfiguration at the exposedPorts stream, then trace the dependsOn and parallel GenericContainer.start paths shown in the report. Reproduce the PostgreSQL/application setup with containersToStart.parallelStream().forEach(GenericContainer::start), and consider the issue complete when dependent containers start without ConcurrentModificationException.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, java
- Domain
- devops, testing
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100