1
votes

Ok, so this is driving me insane!! Can't figure it out.

I've got a spring boot rest webservice which needs to run 24/7. I connects to mysql using a connection pool(using hikariCP).

Currently in dev env its only running a job once a day. So for 23+ hrs the connections are idle.

When the scheduled job runs, it is running on an idle thread for some reason and throws the below exception, even though before it Hikari clearly shows its created a new connection, within the timeout threshold.

I can't reproduce this myself after a few mins/hour of idling, it only happens after this extended period. I've tried following settings from multiple suggestions on other posts/sites, but I'm getting no where. Hoping this is something simple I have overlooked which someone can help me with.

Thanks

2018-10-05 23:00:04 DEBUG HikariPool:411 - secondary - Before cleanup stats (total=2, active=1, idle=1, waiting=0)
2018-10-05 23:00:04 DEBUG HikariPool:411 - secondary - After cleanup  stats (total=2, active=1, idle=1, waiting=0)
2018-10-05 23:00:04 DEBUG HikariPool:411 - primary - Before cleanup stats (total=2, active=1, idle=1, waiting=0)
2018-10-05 23:00:04 DEBUG HikariPool:411 - primary - After cleanup  stats (total=2, active=1, idle=1, waiting=0)
2018-10-05 23:00:13 DEBUG PoolBase:129 - primary - Closing connection com.mysql.jdbc.JDBC4Connection@500889cc: (connection has passed maxLifetime)
2018-10-05 23:00:13 DEBUG HikariPool:709 - primary - Added connection com.mysql.jdbc.JDBC4Connection@2afe5087
2018-10-05 23:00:21 DEBUG OrderedRequestContextFilter:114 - Bound request context to thread: org.apache.catalina.connector.RequestFacade@59f98ac5
2018-10-05 23:00:22 DEBUG HikariPool:709 - secondary - Added connection com.mysql.jdbc.JDBC4Connection@7c42a6a6
2018-10-05 23:00:22 DEBUG PoolBase:129 - secondary - Closing connection com.mysql.jdbc.JDBC4Connection@6add6002: (connection has passed maxLifetime)
2018-10-05 23:00:23 DEBUG DefaultListableBeanFactory:254 - Returning cached instance of singleton bean 'myResource'
2018-10-05 23:00:23 DEBUG DefaultListableBeanFactory:254 - Returning cached instance of singleton bean 'postExecutor'
2018-10-05 23:00:23 DEBUG DefaultListableBeanFactory:254 - Returning cached instance of singleton bean 'myMessageImpl'
2018-10-05 23:00:28 WARN  ProxyConnection:153 - secondary - Connection com.mysql.jdbc.JDBC4Connection@f8c1ddd marked as broken because of SQLSTATE(08S01), ErrorCode(0)
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 44,220,394 milliseconds ago.  The last packet sent successfully to the server was 44,220,395 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
        at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:990)
        at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3749)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2512)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2683)
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2486)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1858)
        at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1966)
        at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
        at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
        at com.jersey.myqueryservice.dao.myMessageImpl.ismyRunning(myMessageImpl.java:61)
        at com.jersey.myqueryservice.dao.myMessageImpl$$FastClassBySpringCGLIB$$a8afcfbf.invoke(<generated>)
.....
Caused by: java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3731)
        ... 80 more

MySQL properties:

mysql> show variables like '%timeout%';
+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| connect_timeout             | 10       |
| delayed_insert_timeout      | 300      |
| have_statement_timeout      | YES      |
| innodb_flush_log_at_timeout | 1        |
| innodb_lock_wait_timeout    | 50       |
| innodb_rollback_on_timeout  | OFF      |
| interactive_timeout         | 28800    |
| lock_wait_timeout           | 31536000 |
| net_read_timeout            | 30       |
| net_write_timeout           | 60       |
| rpl_stop_slave_timeout      | 31536000 |
| slave_net_timeout           | 60       |
| wait_timeout                | 28800    |
+-----------------------------+----------+
13 rows in set (0.01 sec)

Properties:

primary.database.validation-query=SELECT 1
primary.database.max-active=2
primary.database.min-idle=1
primary.database.connection-timeout=14400
primary.database.idle-timeout=14400
primary.database.max-life-time=20000

secondary.database.validation-query=SELECT 1
secondary.database.max-active=5
secondary.database.min-idle=1
secondary.database.connection-timeout=14400
secondary.database.idle-timeout=14400
secondary.database.max-life-time=20000
secondary.database.url=jdbc:mysql://localhost:3306/db?autoReconnect=true

Beans:

@Bean(name = "primaryDatabaseConnection")
    public Connection primaryDatabaseConnection() throws SQLException

    {
        return primaryDataSource().getConnection();
    }

    @Bean(name = "secondaryDatabaseConnection")
    public Connection secondaryDatabaseConnection() throws SQLException
    {

        return secondaryDataSource().getConnection();
    }

    @Bean
    public DataSource primaryDataSource() {

        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName("com.mysql.jdbc.Driver");
        hikariConfig.setJdbcUrl(primaryUrl);
        hikariConfig.setUsername(primaryUser);
        hikariConfig.setPassword(primaryPassword);
        hikariConfig.setMaximumPoolSize(primaryDatabaseMaxActive);
        hikariConfig.setMinimumIdle(primaryDatabaseMinIdle);
        hikariConfig.setConnectionTimeout(primaryDatabaseConnectionTimeout);
        hikariConfig.setMaxLifetime(primaryMaxLifeTime);
        hikariConfig.setIdleTimeout(primaryDatabaseIdleTimeout);
        hikariConfig.setConnectionTestQuery(primaryDatabaseValidationQuery);
        hikariConfig.setPoolName("primary");

        HikariDataSource ds = new HikariDataSource(hikariConfig);
        return ds;
    }


    @Bean
    public DataSource secondaryDataSource() {

        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName("com.mysql.jdbc.Driver");
        hikariConfig.setJdbcUrl(secondaryUrl);
        hikariConfig.setUsername(secondaryUser);
        hikariConfig.setPassword(secondaryPassword);
        hikariConfig.setMaximumPoolSize(secondaryDatabaseMaxActive);
        hikariConfig.setMinimumIdle(secondaryDatabaseMinIdle);
        hikariConfig.setConnectionTimeout(secondaryDatabaseConnectionTimeout);
        hikariConfig.setMaxLifetime(primaryMaxLifeTime);
        hikariConfig.setIdleTimeout(secondaryDatabaseIdleTimeout);
        hikariConfig.setConnectionTestQuery(secondaryDatabaseValidationQuery);
        hikariConfig.setPoolName("secondary");

        HikariDataSource ds = new HikariDataSource(hikariConfig);
        return ds;
    }

Repository:

    @Autowired
        @Qualifier("secondaryDatabaseConnection")
        private Connection conn;
    .
    .
    .
    try (
                 PreparedStatement preparedStatement = conn.prepareStatement(IS_RUNNING_SQL)) { 
.
.
.
.
1

1 Answers

-1
votes

Poor performance can happen. In spring boot we give milliseconds.You may try this out.

spring.datasource.hikari.connection-timeout = 60000 
spring.datasource.hikari.maximum-pool-size= 15
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.max-lifetime=1200000
spring.datasource.hikari.auto-commit=true