-
Notifications
You must be signed in to change notification settings - Fork 323
Description
When I create a DefaultConnectionContext
with no size specified, it appears that the default configuration creates a pool matching the number of CPUs on your system. (see _DefaultConnectionContext.java and PoolResources.java)
This may work well on a machine with multiple CPUs but we are running this as a BOSH errand where the errand VM is configured to have only 1 CPU. So when we try to do multiple operations in parallel, it appears that if one of the operations takes longer than 45 seconds, then the second operation fails with the exception below.
reactor.core.Exceptions$ReactiveException: java.util.concurrent.TimeoutException: Acquire operation took longer then configured maximum time
at reactor.core.Exceptions.propagate(Exceptions.java:218)
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:117)
at reactor.core.publisher.Mono.blockMillis(Mono.java:1215)
at reactor.core.publisher.Mono.block(Mono.java:1193)
at org.lds.cloudfoundry.configurer.controller.ApplicationController.createApplication(ApplicationController.java:91)
at org.lds.cloudfoundry.configurer.handler.DeploymentStepHandler.createDeployment(DeploymentStepHandler.java:81)
at org.lds.cloudfoundry.configurer.handler.DeploymentStepHandler.handleStep(DeploymentStepHandler.java:50)
at org.lds.cloudfoundry.configurer.controller.MainController.configureCloud(MainController.java:32)
at org.lds.cloudfoundry.configurer.Main$ApplicationStartup.run(Main.java:64)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:791)
... 11 common frames omitted
Caused by: java.util.concurrent.TimeoutException: Acquire operation took longer then configured maximum time
at io.netty.channel.pool.FixedChannelPool.<init>(...)(Unknown Source)
Here is the line where I'm seeing this exception thrown.
cf.applications().start(StartApplicationRequest.builder().name(application.getName()).build()).block();
Here is the line in context with the logging that is happening in parallel. Basically we connect to logging so that log messages from the application will be printed to the console, then we start the application and wait for it to finish. When it is finished, we dispose of the logging.
Disposable logDisposable = null;
try {
LOG.info("Starting application logging: " + application.getName());
LogsRequest logsRequest = LogsRequest.builder().name(application.getName()).build();
logDisposable = cf.applications().logs(logsRequest).subscribe(consumer -> {
if (consumer.getMessageType() == MessageType.ERR) {
LOG.error("\t" + application.getName() + "\t\t| " + consumer.getMessage());
} else {
LOG.info("\t" + application.getName() + "\t\t| " + consumer.getMessage());
}
});
LOG.info("Starting application: " + application.getName());
cf.applications().start(StartApplicationRequest.builder().name(application.getName()).build()).block();
} finally {
if (logDisposable != null) {
LOG.info("Stopping application logging: " + application.getName());
logDisposable.dispose();
}
}
It seems like 45 seconds is the default timeout for acquiring a channel from the pool (see PoolResources.java) and in this case, it takes longer than 45 seconds for the application to start.
When I set the connection pool size > 1 then the issue is resolved
@Bean
public DefaultConnectionContext context(CloudConfigurationPlan cloudConfigurationPlan) {
return DefaultConnectionContext.builder()
.apiHost(cloudConfigurationPlan.getApi())
.connectionPoolSize(2)
.build();
}
Is there something I'm doing wrong here? If not, I recommend either using an elastic pool or changing the default so that it has a sensible minimum (maybe 2?).