I'm trying to have a spring boot app retry to connect to a database when a connection fails and currently have this:
package backend.configuration.dbconnection;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.support.RetryTemplate;
import javax.sql.DataSource;
@Log
@Configuration
@EnableRetry
public class CustomDataSourceConfiguration {
@Autowired
private RetryTemplate retryTemplate;
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
//dataSource.setUrl("jdbc:mysql://localhost:3306/db");
dataSource.setUrl("jdbc:mysql://localhost:3307/db");
dataSource.setUsername("user");
dataSource.setPassword("password");
retryTemplate.execute(context -> {
try {
dataSource.getConnection();
return dataSource;
} catch (Exception e) {
return null;
}
});
return dataSource;
}
}
and this:
package backend.configuration.dbconnection;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
@Configuration
@EnableRetry
public class RetryConfiguration {
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(5);
retryTemplate.setRetryPolicy(retryPolicy);
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(1000);
retryTemplate.setBackOffPolicy(backOffPolicy);
return retryTemplate;
}
}
returning null upon not being able to connect, so that the retry will kick in. This seems to not be the case. How can I fix this?
if you are using spring-boot 3.0.0
/ spring-framkework6.0.0
or higher , you can try to use the retry tools in reactor
which is a non-blocking network framework.
the code snippet is like following
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
//dataSource.setUrl("jdbc:mysql://localhost:3306/db");
dataSource.setUrl("jdbc:mysql://localhost:3307/db");
dataSource.setUsername("user");
dataSource.setPassword("password");
var connectionIsClosed = Mono.just(dataSource)
.map(e -> {
Connection connection = null;
try {
connection = dataSource.getConnection();
var closed = connection.isClosed();
if (!closed) {
return connection;
}
throw new RuntimeException("connection is closed");
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
})
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1)) // retry 3 times, and backoff 1 second
.maxBackoff(Duration.ofSeconds(5)) // max backoff time
.filter(throwable -> throwable instanceof RuntimeException) // it only retry when the exception is RuntimeException
.onRetryExhaustedThrow((spec, rs) -> new ConnectException("remote server is invalid !")) // if retry 3 times and still failed, then throw ConnectException
.doBeforeRetry(retrySignal -> System.out.println("Retrying... connecting to database..."))) // print log before retry
.block();
return dataSource;