For Cloud Foundry-deployed Spring apps with default settings, there may be a warning message in the application log as shown below:
org.apache.tomcat.jdbc.pool.ConnectionPool WARNING maxIdle is larger than maxActive, setting maxIdle to: 4 maxIdle to: 4
Depending upon the application, database usage pattern/demand, this message may be followed by another error message:
org.apache.tomcat.jdbc.pool.PoolExhaustedException: [...] Timeout: Pool empty. Unable to fetch a connection in 30 seconds, none available[size:4; busy:4; idle:0; lastwait:30000]
A Spring app is usually deployed to Cloud Foundry with the Java Buildpack (if no explicit buildpack is mentioned, it would be used as the default buildpack for Java apps). The Java buildpack uses its Spring Auto-reconfiguration framework to make an application automatically reconfigure to use a bound cloud services. It also adds the "cloud" profile as an active Spring profile for the application.
This framework has its own copy of Spring cloud connectors, which along with other things, initializes a Pooled datasource with a size of 4
and maxWaitTime
of 30,000
. This is done so that it would be compatible with the limited free tier services of cloud providers. This setting is usually sufficient for any test or demo projects. But for any serious application, it is best to customize this as per application-needs.
This error message most likely appears, if you are deploying a Spring app to Cloud Foundry and you have a database service bound to the deployed app. In that case, Java Buildpack's Spring Auto-reconfiguration framework reconfigures the datasource with the cloud database service connection properties and ignores all local datasource customization. To remedy this and get more control over datasource properties, there are few options you may use.
This will disable Java Buildpack's Spring Auto-reconfiguration but the warning/error message may still appear if you use Spring Cloud Service Connector but did not supply any pool properties, so it is initialized using default properties.
You can supply the properties either programmatically like this:
//Connect to the 'my-own-personal-sql' relational database service, supplying configuration @Bean public DataSource dataSource() { PoolConfig poolConfig = new PoolConfig(5, 30, 3000); DataSourceConfig dbConfig = new DataSourceConfig(poolConfig, null); return connectionFactory().dataSource("my-own-personal-sql", dbConfig); }
Or if you need more control control over the resource that’s being created you can add @ConfigurationProperties(prefix = <properties prefix>) like this:
@Configuration @Profile("cloud") public class CloudConfig extends AbstractCloudConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.hikari") DataSource dataSource() { return connectionFactory().dataSource(); } }
and then use spring.datasource.hikari.* in your application.properties file
You can disable Java Buildpack's Spring Auto-reconfiguration by setting the app env variable JBP_CONFIG_SPRING_AUTO_RECONFIGURATION
to '{enabled: false}'
(E.g. cf set-env <APP-NAME> JBP_CONFIG_SPRING_AUTO_RECONFIGURATION '{enabled: false}'
)
With this option, you can fully configure the DataSource
properties in your application.properties or application.yml
. The downside is that you don’t get the “cloud” profile enabled automatically or the cloud.*
property placeholder values. Thus you also have to set an env variable to enable the “cloud” profile (E.g. cf set-env <APP-NAME> SPRING_PROFILES_ACTIVE cloud
)
If you are using Spring Boot, it does give you some help to configure DataSource credentials. It will read VCAP_SERVICES
and expose it through a vcap.services.*
property placeholder. These place holders can then be used to configure your services. There is a good example in this article and also in this article.
Whatever datasource properties you mention, be sure that those are within limits of the service plan you created in Cloud Foundry.