Spring boot hikaricp connection-timeout vs connectionTimeout - spring-boot

when I google the Hikaricp connection properties, I found two major difference, for example:
https://www.javadevjournal.com/spring-boot/spring-boot-hikari/
https://www.baeldung.com/spring-boot-hikari
spring.datasource.hikari.connection-timeout = 20000
spring.datasource.hikari.connectionTimeout=30000
when I look into https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby
I cannot find '''.connection-timeout'''
what is the difference between connection-timeout vs connectionTimeout?
this is one of the difference I found on net. 😒

Spring Boot utilized something they call relaxed binding and each of those properties would endup in the same place. The connectionTimeout property of the HikariDataSource.
In fact you could also use _ or when providing a environment variable use uppercase names.
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.connection_timeout=20000
spring.datasource.hikari.connectionTimeout=30000
SPRING_DATASOURCE_HIKARI_CONNECTIONTIMEOUT=30000
All of the aforementioned properties would eventually be bound to the HikariDataSource.connectionTimeout property. They are all different representations of the same. The latter is mainly to overcome the limitation of not being able to use - in environment variables in Linux/Mac.

Here is the actual code in Hikari - setting up the configuration and the actual property is connectionTimeout. Spring would most likely invoke it via setter when provided this setting in Spring configuration
public class HikariConfig implements HikariConfigMXBean
{
.....................
.....................
private volatile long connectionTimeout;
/** {#inheritDoc} */
#Override
public long getConnectionTimeout()
{
return connectionTimeout;
}
/** {#inheritDoc} */
#Override
public void setConnectionTimeout(long connectionTimeoutMs)
{
if (connectionTimeoutMs == 0) {
this.connectionTimeout = Integer.MAX_VALUE;
}
else if (connectionTimeoutMs < 250) {
throw new IllegalArgumentException("connectionTimeout cannot be less than 250ms");
}
else {
this.connectionTimeout = connectionTimeoutMs;
}
}

Related

Why Querydsl always requires connection to be transactional?

Recently I tried a new tool for db access called Querydsl in my Spring Boot app, here is how I configure the context in #Configuration class:
#Bean
public com.querydsl.sql.Configuration querydslConfiguration() {
SQLTemplates templates = OracleTemplates.builder().build();
com.querydsl.sql.Configuration configuration = new com.querydsl.sql.Configuration(templates);
configuration.setExceptionTranslator(new SpringExceptionTranslator());
return configuration;
}
#Bean
public SQLQueryFactory queryFactory(DataSource dataSource) {
Provider<Connection> provider = new SpringConnectionProvider(dataSource);
return new SQLQueryFactory(querydslConfiguration(), provider);
}
My query is a quite simple select:
fun detailedEntityByIds(ids: Set<String>): List<DetailedEntity> {
val qDetails = QTContainerDetails.tContainerDetails
return sqlQueryFactory.select(qDetails).from(qDetails)
.where(qDetails.id.`in`(ids))
.fetch().map { mapper.qDslEntToModel(it) }
}
Then I faced with was the following exception:
java.lang.IllegalStateException: Connection is not transactional
I quickly found this question: [QueryDSL/Spring]java.lang.IllegalStateException: Connection is not transactional with an advice to use #Transactional for solving this problem.
Why does Querydsl requires connections to be transactional? I used to put #Transactional on a service layer methods where I really need it. Now Querydsl 'forces' me to put it on a whole DAO class, because looks like it is required for every Querydsl query.
From the Javadoc
/**
* {#code SpringConnectionProvider} is a Provider implementation which provides a transactionally bound connection
*
* <p>Usage example</p>
* <pre>
* {#code
* Provider<Connection> provider = new SpringConnectionProvider(dataSource());
* SQLQueryFactory queryFactory = SQLQueryFactory(configuration, provider);
* }
* </pre>
*/
The reason is for resource management. You don't have access to the underlying JDBC implementation. The transaction will close ResultSets, Statements, Connections, etc. Without a transaction, every connection would be left open, the connection pool saturated, the database running out of resources, etc.
If you want to manage your own resources, you could write your own Provider<Connection> and pass in the DataSource E.G.
private static Provider<Connection> getConnection(DataSource dataSource) {
return () -> org.springframework.jdbc.datasource.DataSourceUtils.getConnection(dataSource);
}

Spring configuration / properties different per request

I need to figure out if the following scenario is possible in Spring.
If we have different services / databases per region, can Spring facilitate directing calls to those services / databases per request from a single deployment? To give an example, all requests from user X will be directed to services / databases in the EAST region while all requests from user Y will be directed to services / databases in the WEST region.
Obviously connections to each database will use connection pooling, so the configuration will need to differ, not just properties. When other services are initialized, there is authentication done, so it's not just about databases connections.
This being Spring, I'd like to avoid having to pass implementations around. Can I direct Spring to use a specific configuration per request? Is there a better way to accomplish this?
-- Edit --
Technically it can be done like this, though this isn't exactly easily maintainable.
#Configuration
#PropertySource("classpath:region1.properties")
public class TestIndependentConfigurationRegion1Configuration {
#Bean
public String sampleServiceUrl(#Value("${sample.service.url}") String value) {
return value;
}
#Bean
public TestIndependentConfigurationSampleService testSampleService() {
return new TestIndependentConfigurationSampleService();
}
}
#Configuration
#PropertySource("classpath:region2.properties")
public class TestIndependentConfigurationRegion2Configuration {
#Bean
public String sampleServiceUrl(#Value("${sample.service.url}") String value) {
return value;
}
#Bean
public TestIndependentConfigurationSampleService testSampleService() {
return new TestIndependentConfigurationSampleService();
}
}
#Controller
public class TestIndependentConfigurationController {
protected ApplicationContext testRegion1ApplicationContext = new AnnotationConfigApplicationContext(TestIndependentConfigurationRegion1Configuration.class);
protected ApplicationContext testRegion2ApplicationContext = new AnnotationConfigApplicationContext(TestIndependentConfigurationRegion2Configuration.class);
#RequestMapping("/sample/service")
#ResponseBody
public String testSampleService() {
TestIndependentConfigurationSampleService testSampleService = null;
if(/* region 1 */) {
testSampleService = (TestIndependentConfigurationSampleService) testRegion1ApplicationContext.getBean("testSampleService");
}
if(/* region 2 */) {
testSampleService = (TestIndependentConfigurationSampleService) testRegion2ApplicationContext.getBean("testSampleService");
}
testSampleService.executeSampleService();
return "SUCCESS";
}
}
I don't think you can do that with properties. BUT, you should look at (netflix) ribbon client that is integrated with spring. Some of the ribbon's features allow you to load balance request's between regions. You could customize the ribbon client to do what you want.
Some readings here :
https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html

Spring Boot auto-configured metrics not arriving to Librato

I am using Spring Boot with auto-configure enabled (#EnableAutoConfiguration) and trying to send my Spring MVC metrics to Librato. Right now only my own created metrics are arriving to Librato but auto-configured metrics (CPU, file descriptors, etc) are not sent to my reporter.
If I access a metric endpoint I can see the info generated there, for instance http://localhost:8081/actuator/metrics/system.cpu.count
I based my code on this post for ConsoleReporter. so I have this:
public static MeterRegistry libratoRegistry() {
MetricRegistry dropwizardRegistry = new MetricRegistry();
String libratoApiAccount = "xx";
String libratoApiKey = "yy";
String libratoPrefix = "zz";
LibratoReporter reporter = Librato
.reporter(dropwizardRegistry, libratoApiAccount, libratoApiKey)
.setPrefix(libratoPrefix)
.build();
reporter.start(60, TimeUnit.SECONDS);
DropwizardConfig dropwizardConfig = new DropwizardConfig() {
#Override
public String prefix() {
return "myprefix";
}
#Override
public String get(String key) {
return null;
}
};
return new DropwizardMeterRegistry(dropwizardConfig, dropwizardRegistry, HierarchicalNameMapper.DEFAULT, Clock.SYSTEM) {
#Override
protected Double nullGaugeValue() {
return null;
}
};
}
and at my main function I added Metrics.addRegistry(SpringReporter.libratoRegistry());
For the Librato library I am using in my compile("com.librato.metrics:metrics-librato:5.1.2") build.gradle. Documentation here. I used this library before without any problem.
If I use the ConsoleReporter as in this post the same thing happens, only my own created metrics are printed to the console.
Any thoughts on what am I doing wrong? or what am I missing?
Also, I enabled debug mode to see the "CONDITIONS EVALUATION REPORT" printed in the console but not sure what to look for in there.
Try to make your MeterRegistry for Librato reporter as a Spring #Bean and let me know whether it works.
UPDATED:
I tested with ConsoleReporter you mentioned and confirmed it's working with a sample. Note that the sample is on the branch console-reporter, not the master branch. See the sample for details.

no logging for PerformanceMonitorInterceptor

I've got this simple bean for PerformanceMonitorInterceptor
#Configuration
#EnableAspectJAutoProxy
#Aspect
public class PerfMetricsConfiguration {
/**
* Monitoring pointcut.
*/
#Pointcut("execution(* com.lapots.breed.judge.repository.*Repository.*(..))")
public void monitor() {
}
/**
* Creates instance of performance monitor interceptor.
* #return performance monitor interceptor
*/
#Bean
public PerformanceMonitorInterceptor performanceMonitorInterceptor() {
return new PerformanceMonitorInterceptor(true);
}
/**
* Creates instance of performance monitor advisor.
* #return performance monitor advisor
*/
#Bean
public Advisor performanceMonitorAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("com.lapots.breed.judge.repository.PerfMetricsConfiguration.monitor()");
return new DefaultPointcutAdvisor(pointcut, performanceMonitorInterceptor());
}
}
It supposed to trace any method invocation in the interfaces that ends with Repository in name.
I set logging level in application.properties
logging.level.org.springframework.aop.interceptor.PerformanceMonitorInterceptor=TRACE
But during execution it doesn't write anything in the console. What's the problem?
I was facing similar issue, after changing the useDynamicLogger to false the issue was fixed.
#Bean
public PerformanceMonitorInterceptor performanceMonitorInterceptor() {
return new PerformanceMonitorInterceptor(false);
}
Faced with the same issue. And as Manzoor suggested passing false to PerformanceMonitorInterceptor solves the problem.
Why? When you call new PerformanceMonitorInterceptor(true), the logger name used inside of PerformanceMonitorInterceptor will be: com.lapots.breed.judge.repository.SomeClass.
So in your particular case the following logging configuration is required:
logging.level.com.lapots.breed.judge.repository=TRACE, otherwise you do not see any logs, the breakpoint on PerformanceMonitorInterceptor.invokeUnderTrace() will not work and you spend lot's of time thinking you have wrong AOP configuration (while actually it's fine), but you did not set up logging level for proper class/package.
I am using spring logging (SLF4J logging). Instead of putting PerformanceMonitorInterceptor logger to TRACE , I added com.lapots.breed.judge.repository logger to TRACE.
This started printing logs for me.
I did this because the below method in AbstractTraceInterceptor is looking for TRACE enabled on the class(Repository) we executing but not on PerformanceMonitorInterceptor.
protected boolean isLogEnabled(Log logger) {
return logger.isTraceEnabled();
}
I just tried this, I simply added this to application.properties and it works:
logging.level.org.springframework.aop.interceptor.PerformanceMonitorInterceptor=trace

Remote PropertySource

Has anyone had any luck constructing a PropertySource that uses a remote source (for example a database) from which to retrieve property values. The idea would be to construct a PropertySource (needs some connection information such as host/port) and plug that into a PropertySourcePlaceholderConfigurer.
The problem seems to be a chicken and egg problem. How can I get the connection information down to the PropertySource? I could first instantiate the PropertySourcePlaceholderConfigurer with configuration to load a property file with the remote host and port properties and then later instantiate the PropertySource and inject that back into the configurer. However, I can't seem to figure a way to ensure that the very first bean to be instantiated (and quickly injected into the configurer) is my property source. I need to have this because, of course, all my other beans depend on the remote properties.
Commons Configuration supports loading properties from a variety of sources (including JDBC Datasources) into a org.apache.commons.configuration.Configuration object via a org.apache.commons.configuration.ConfigurationBuilder.
Using the org.apache.commons.configuration.ConfiguratorConverter, you can convert the Configuration object into a java.util.Properties object which can be passed to the PropertySourcesPlaceholderConfigurer.
As to the chicken and egg question of how to configure the ConfigurationBuilder, I recommend using the org.springframework.core.env.Environment to query for system properties, command-line properties or JNDI properties.
In this exampe:
#Configuration
public class RemotePropertyConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer(Environment environment)
throws Exception {
final PropertySourcesPlaceholderConfigurer props = new PropertySourcesPlaceholderConfigurer();
final ConfigurationBuilder configurationBuilder = new DefaultConfigurationBuilder(environment.getProperty("configuration.definition.file"));
props.setProperties(ConfigurationConverter.getProperties(configurationBuilder.getConfiguration()));
return props;
}
You will need to specify the environment property configuration.definition.file which points to a file needed to configure Commons Configuration:
Similar to Recardo's answer above, I used Spring's PropertiesLoaderUtils instead of Apache's, but it amounts to the same thing. It's not exactly ideal.. hard coded dependency injection, but hey, it works!
/**
* This method must remain static as it's part of spring's initialization effort.
* #return
**/
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
String dbHost = null;
Integer dbPort = null;
// check system / environment properties first
Environment environment = new StandardEnvironment();
if (environment.containsProperty(DB_HOST_KEY)) {
dbHost = environment.getProperty(DB_HOST_KEY);
}
if (environment.containsProperty(DB_PORT_KEY)) {
dbPort = Integer.valueOf(environment.getProperty(DB_PORT_KEY));
}
if (dbHost == null || dbPort == null) {
// ok one or (probably) both properties null, let's go find the database.properties file
Properties dbProperties;
try {
dbProperties = PropertiesLoaderUtils.loadProperties(new EncodedResource(new ClassPathResource("database.properties"), "UTF-8"));
}
catch (IOException e) {
throw new RuntimeException("Could not load database.properties. Please confirm the file is in the classpath");
}
if (dbHost == null) {
dbHost = dbProperties.getProperty(DB_HOST_KEY);
}
if (dbPort == null) {
dbPort = Integer.valueOf(dbProperties.getProperty(DB_PORT_KEY));
}
}
PropertySourceService propertySourceService = new DBPropertySourceService(dbHost, dbPort);
PropertySource<PropertySourceService> propertySource = new DBPropertySource(propertySourceService);
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(propertySource);
configurer.setPropertySources(propertySources);
return configurer;
}
per request, here is the source of the remote property source. It depends on a 'service' class that might do.. well.. anything.. remote access of a property over a socket, talk to a database, whatever.
/**
* Property source for use with spring's PropertySourcesPlaceholderConfigurer where the source is a service
* that connects to remote server for property values.
**/
public class RemotePropertySource extends PropertySource<PropertySourceService> {
private final Environment environment;
/**
* Constructor...
* #param name
* #param source
**/
public RemotePropertySource(PropertySourceService source) {
super("RemotePropertySource", source);
environment = new StandardEnvironment();
}
/* (non-Javadoc)
* #see org.springframework.core.env.PropertySource#getProperty(java.lang.String)
*/
#Override
public Object getProperty(String name) {
// check system / environment properties first
String value;
if (environment.containsProperty(name)) {
value = environment.getProperty(name);
}
else {
value = source.getProperty(name);
}
return value;
}
}

Resources