简体   繁体   中英

How to simulate lost database connection locally?

There is a SpringBoot-based application running on a server which regularly inserts/updates records in a relational database.

The database connection is set up like this:

import org.springframework.context.annotation.Bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.sql.DataSource;

[...]

@Configuration
@EnableConfigurationProperties
public class DbConfigClass {

    [...]

    @Bean(name = "myDataSource")
    @ConfigurationProperties(prefix = "com.mycompany.somedatabase")
    public DataSource dsSomeDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    [...]
}

Sometimes the connection is interrupted in irregular, unpredictable intervals. Then, I get errors like this:

java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available,
request timed out after 30001ms.

at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:694)

I need to make sure that my application can deal with such interruptions. To do so, I need to be able to reproduce this behavior locally.

How can I do it?

I looked at ToxyProxy which seems to do what I want.

However, I am wondering whether or not I can simulate such conditions with less effort, eg by using Mockito.spy to modify the data source so that it sometimes throws the exception above.

Found an easy and seemingly good-enough solution:

First I created a class whose getConnection method throws an exception in every second call:

public class ShakyDataSource implements DataSource {
    private final DataSource ds;
    private AtomicLong getConnectionCallsCount = new AtomicLong(1);
    
    public ShakyDataSource(final DataSource ds) {
        this.ds = ds;
    }
    
    @Override
    public Connection getConnection() throws SQLException {
        final long newGetConnectionCallCount = getConnectionCallsCount.incrementAndGet();
        
        if ((newGetConnectionCallCount % 2) == 0) {
            throw new SQLException("Simulated connection failure");
        }
        else {
            return ds.getConnection();
        }
    }
    
    // All other methods of DataSource call corresponding methods of ds
}

Then I modified the configuration like this:

import org.springframework.context.annotation.Bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.sql.DataSource;

[...]

@Configuration
@EnableConfigurationProperties
public class DbConfigClass {

    [...]

    @Bean(name = "myDataSource")
    @ConfigurationProperties(prefix = "com.mycompany.somedatabase")
    public DataSource dsSomeDataSource() {
        if (SIMULATE_SHAKY_CONNECTION) {
            LOGGER.error("Don't do this in production!");
            return new ShakyDataSource(DataSourceBuilder.create().build());
        }
        return DataSourceBuilder.create().build();
    }
    
    [...]
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM