Refine container initialization and parallel startup logic
Update `TestcontainersLifecycleBeanPostProcessor` to restore early container initialization logic and refine startup logic. Initial bean access now again triggers the creation all container beans. In addition the first access of a `Startable` bean now attempts to find and start all other `Startable` beans. Fixes gh-37989
This commit is contained in:
parent
efb5cb0bcd
commit
0c66db7b18
|
@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
@ -62,7 +63,9 @@ class TestcontainersLifecycleBeanPostProcessor implements DestructionAwareBeanPo
|
||||||
|
|
||||||
private final TestcontainersStartup startup;
|
private final TestcontainersStartup startup;
|
||||||
|
|
||||||
private volatile boolean containersInitialized = false;
|
private final AtomicBoolean startablesInitialized = new AtomicBoolean();
|
||||||
|
|
||||||
|
private final AtomicBoolean containersInitialized = new AtomicBoolean();
|
||||||
|
|
||||||
TestcontainersLifecycleBeanPostProcessor(ConfigurableListableBeanFactory beanFactory,
|
TestcontainersLifecycleBeanPostProcessor(ConfigurableListableBeanFactory beanFactory,
|
||||||
TestcontainersStartup startup) {
|
TestcontainersStartup startup) {
|
||||||
|
@ -72,38 +75,34 @@ class TestcontainersLifecycleBeanPostProcessor implements DestructionAwareBeanPo
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||||
if (!this.containersInitialized && this.beanFactory.isConfigurationFrozen()) {
|
if (this.beanFactory.isConfigurationFrozen() && this.containersInitialized.compareAndSet(false, true)) {
|
||||||
initializeContainers();
|
initializeContainers();
|
||||||
}
|
}
|
||||||
|
if (bean instanceof Startable startableBean) {
|
||||||
|
if (this.startablesInitialized.compareAndSet(false, true)) {
|
||||||
|
initializeStartables(startableBean, beanName);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
startableBean.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeContainers() {
|
private void initializeStartables(Startable startableBean, String startableBeanName) {
|
||||||
Set<String> beanNames = new LinkedHashSet<>();
|
List<String> beanNames = new ArrayList<>(
|
||||||
beanNames.addAll(List.of(this.beanFactory.getBeanNamesForType(ContainerState.class, false, false)));
|
List.of(this.beanFactory.getBeanNamesForType(Startable.class, false, false)));
|
||||||
beanNames.addAll(List.of(this.beanFactory.getBeanNamesForType(Startable.class, false, false)));
|
beanNames.remove(startableBeanName);
|
||||||
initializeContainers(beanNames);
|
List<Object> beans = getBeans(beanNames);
|
||||||
}
|
if (beans == null) {
|
||||||
|
this.startablesInitialized.set(false);
|
||||||
private void initializeContainers(Set<String> beanNames) {
|
|
||||||
List<Object> beans = new ArrayList<>(beanNames.size());
|
|
||||||
for (String beanName : beanNames) {
|
|
||||||
try {
|
|
||||||
beans.add(this.beanFactory.getBean(beanName));
|
|
||||||
}
|
|
||||||
catch (BeanCreationException ex) {
|
|
||||||
if (ex.contains(BeanCurrentlyInCreationException.class)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw ex;
|
beanNames.add(startableBeanName);
|
||||||
}
|
beans.add(startableBean);
|
||||||
}
|
|
||||||
if (!this.containersInitialized) {
|
|
||||||
this.containersInitialized = true;
|
|
||||||
if (!beanNames.isEmpty()) {
|
|
||||||
logger.debug(LogMessage.format("Initialized container beans '%s'", beanNames));
|
|
||||||
}
|
|
||||||
start(beans);
|
start(beans);
|
||||||
|
if (!beanNames.isEmpty()) {
|
||||||
|
logger.debug(LogMessage.format("Initialized and started startable beans '%s'", beanNames));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +114,29 @@ class TestcontainersLifecycleBeanPostProcessor implements DestructionAwareBeanPo
|
||||||
this.startup.start(startables);
|
this.startup.start(startables);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initializeContainers() {
|
||||||
|
List<String> beanNames = List.of(this.beanFactory.getBeanNamesForType(ContainerState.class, false, false));
|
||||||
|
if (getBeans(beanNames) == null) {
|
||||||
|
this.containersInitialized.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Object> getBeans(List<String> beanNames) {
|
||||||
|
List<Object> beans = new ArrayList<>(beanNames.size());
|
||||||
|
for (String beanName : beanNames) {
|
||||||
|
try {
|
||||||
|
beans.add(this.beanFactory.getBean(beanName));
|
||||||
|
}
|
||||||
|
catch (BeanCreationException ex) {
|
||||||
|
if (ex.contains(BeanCurrentlyInCreationException.class)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return beans;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean requiresDestruction(Object bean) {
|
public boolean requiresDestruction(Object bean) {
|
||||||
return bean instanceof Startable;
|
return bean instanceof Startable;
|
||||||
|
|
Loading…
Reference in New Issue