When reusable mode is specified, Testcontainers will keep containers between JVM runs, allowing for much faster iterations. But Spring Boot forces containers to be terminated.
In fact, GenericContainer already implements AutoCloseable and Spring will destroy it automatically without TestcontainersLifecycleBeanPostProcessor, but at least that behavior can be turned off with @Bean(destroyMethod = ""). However, TestcontainersLifecycleBeanPostProcessor forces the destruction no matter what user config is specified.
Proposed solution: delegate to Spring's AutoCloseable support, allowing destroyMethod to be set.
Comment From: philwebb
I think #35120 should have fixed this, but I wonder if we can do better? It would be nice if users didn't need to remember to set destroyMethod. @bsideup Is there any way to tell that a container is due to be reused and shouldn't be closed? How does the TestcontainersExtension JUnit extension deal with this?
Comment From: bsideup
@philwebb ah, good to know! I need to switch to SNAPSHOTs 👍
There is #isShouldBeReused (the name is weird as it is auto-generated by Lombok, but it is what it is :D).
TestcontainersExtension does not handle reusable containers, it calls both start() and stop() without exceptions. Usually, reusable containers would be defined as a singleton, but Spring Boot's support makes it too appealing to have the framework start them :)
Comment From: eddumelendez
I can confirm the issue is still there due to Startable implements close method which calls stop. So, @Bean(destroyMethod = "") does the trick
Comment From: eddumelendez
In the past, I was considering doing something like this
@Bean
ContainerBootstrap mysql() {
return new ContainerBootstrap(new MySQLContainer<>());
}
public class ContainerBootstrap implements SmartLifecycle {
private final GenericContainer<?> container;
public ContainerBootstrap(GenericContainer<?> container) {
Assert.notNull(container, "container must not be null");
this.container = container;
}
@Override
public void start() {
this.container.start();
}
@Override
public void stop() {
if (!this.container.isShouldBeReused()) {
this.container.stop();
}
}
}
In this case, close is delegated to the ContainerBootstrap which will handle stopping the containers if it is not reusable instead of GenericContainer directly.