Skip to content

Make GenericContainer.start() and stop() thread-safe#11702

Open
remal wants to merge 1 commit intotestcontainers:mainfrom
remal:fix/thread-safe-container-start
Open

Make GenericContainer.start() and stop() thread-safe#11702
remal wants to merge 1 commit intotestcontainers:mainfrom
remal:fix/thread-safe-container-start

Conversation

@remal
Copy link
Copy Markdown

@remal remal commented Apr 13, 2026

Summary

GenericContainer.start() guards against double-start with if (containerId != null) return, but start() is not synchronized. When two threads call start() on the same container concurrently, both can pass the guard before either sets containerId, creating two Docker containers for one logical dependency.

This can happen when @Testcontainers is used and the container is also started from another context. In our case, we have custom test infrastructure that handles @Container annotations and starts containers. It does not cover all use-cases, so some test classes still need to use @Testcontainers. When both the custom infrastructure and the extension call start() on the same container, they race.

The workaround is to not annotate dependencies with @Container, but this is not obvious to developers and error-prone.

The fix adds @Synchronized to start() and stop() in GenericContainer and all other Startable implementations that override these methods. containerId is also made volatile for cross-thread visibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant