-
Notifications
You must be signed in to change notification settings - Fork 40.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
1 changed file
with
45 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ | |
import java.util.LinkedHashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import java.util.stream.Collectors; | ||
|
||
import org.apache.commons.logging.Log; | ||
|
@@ -62,7 +63,9 @@ class TestcontainersLifecycleBeanPostProcessor implements DestructionAwareBeanPo | |
|
||
private final TestcontainersStartup startup; | ||
|
||
private volatile boolean containersInitialized = false; | ||
private final AtomicBoolean startablesInitialized = new AtomicBoolean(); | ||
|
||
private final AtomicBoolean containersInitialized = new AtomicBoolean(); | ||
|
||
TestcontainersLifecycleBeanPostProcessor(ConfigurableListableBeanFactory beanFactory, | ||
TestcontainersStartup startup) { | ||
|
@@ -72,47 +75,66 @@ class TestcontainersLifecycleBeanPostProcessor implements DestructionAwareBeanPo | |
|
||
@Override | ||
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(); | ||
} | ||
if (bean instanceof Startable startableBean) { | ||
if (this.startablesInitialized.compareAndSet(false, true)) { | ||
initializeStartables(startableBean, beanName); | ||
} | ||
else { | ||
startableBean.start(); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
philwebb
Author
Member
|
||
} | ||
} | ||
return bean; | ||
} | ||
|
||
private void initializeStartables(Startable startableBean, String startableBeanName) { | ||
List<String> beanNames = new ArrayList<>( | ||
List.of(this.beanFactory.getBeanNamesForType(Startable.class, false, false))); | ||
beanNames.remove(startableBeanName); | ||
List<Object> beans = getBeans(beanNames); | ||
if (beans == null) { | ||
this.startablesInitialized.set(false); | ||
return; | ||
} | ||
beanNames.add(startableBeanName); | ||
beans.add(startableBean); | ||
start(beans); | ||
if (!beanNames.isEmpty()) { | ||
logger.debug(LogMessage.format("Initialized and started startable beans '%s'", beanNames)); | ||
} | ||
} | ||
|
||
private void start(List<Object> beans) { | ||
Set<Startable> startables = beans.stream() | ||
.filter(Startable.class::isInstance) | ||
.map(Startable.class::cast) | ||
.collect(Collectors.toCollection(LinkedHashSet::new)); | ||
this.startup.start(startables); | ||
} | ||
|
||
private void initializeContainers() { | ||
Set<String> beanNames = new LinkedHashSet<>(); | ||
beanNames.addAll(List.of(this.beanFactory.getBeanNamesForType(ContainerState.class, false, false))); | ||
beanNames.addAll(List.of(this.beanFactory.getBeanNamesForType(Startable.class, false, false))); | ||
initializeContainers(beanNames); | ||
List<String> beanNames = List.of(this.beanFactory.getBeanNamesForType(ContainerState.class, false, false)); | ||
if (getBeans(beanNames) == null) { | ||
this.containersInitialized.set(false); | ||
} | ||
} | ||
|
||
private void initializeContainers(Set<String> beanNames) { | ||
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; | ||
return null; | ||
} | ||
throw ex; | ||
} | ||
} | ||
if (!this.containersInitialized) { | ||
this.containersInitialized = true; | ||
if (!beanNames.isEmpty()) { | ||
logger.debug(LogMessage.format("Initialized container beans '%s'", beanNames)); | ||
} | ||
start(beans); | ||
} | ||
} | ||
|
||
private void start(List<Object> beans) { | ||
Set<Startable> startables = beans.stream() | ||
.filter(Startable.class::isInstance) | ||
.map(Startable.class::cast) | ||
.collect(Collectors.toCollection(LinkedHashSet::new)); | ||
this.startup.start(startables); | ||
return beans; | ||
} | ||
|
||
@Override | ||
|
Hello, @philwebb I,m interesting this line, when start again