Delay SpringBoot application startup until db is up - java

I have a SpringBoot application that will fail to start up when the database it is using is not up since the datasource bean will fail to initialize. I want for my application to not start before my db is up in order to avoid this failure.
To mention that this app is running in Kubernetes so one option would be to use an init-container. I would want though to have that logic inside the application itself.
First of all, is that a bad idea and I should stick with init-containers?
If it is not a bad idea what is usually the best approach for this. I was looking at Spring Retry and one possible solution seems to be to have retry logic in the #Bean datasource initialization method. Does that have any possible drawbacks? Is there a better way?

Not sure if this works for you but in case you have Data source beans declared.
You can you #Lazy annotation to delay the bean initialization until required.
Your application startup shouldn't fail on startup as the Datasource bean would not be initialized until needed

You can have a startup probe to check DB connections at the start. If you want the DB connections to be constantly pooled for health, you can use other probles. Or in the pipeline which you use to deploy, after the check build unittest phases, you can add a step to check connections of external services/db which you use.

Related

Flyway, spring boot and application start without database

I'm trying to make Spring Boot application with Flyway (and Hikari pool) to start the server even when the DB is not available at that time.
I need to support cases when:
1. DB is not available when applicaition starts (it should run Flyway after DB starts, it can be up to 30 mins).
2. DB goes offline during the application lifetime and then goes back up.
I got a problem with the first case, Flyway always tries to do migrations even when DB is not available and application stops.
I tried adding spring.datasource.continue-on-error: true but Flyway ignores that, and I couldn't find any flyway configuration that would allow such operation.
Is it possible or should I wrap Flyway and do it myself?
Spring boot 2.1.4
A couple of points to consider
What is the desired behavior of the application when the DB is really not available when the instance of java application? Ok, so flyway won't start, but how the application will be able to handle requests that will have to reach the database?
Flyway itself relies on DataSource bean, maybe on hibernate if you use it, and these are much more complicated infrastructures than flyway itself?
Maybe if the database is not available the application won't need to start at all?
Instead it worth to rely on orchestrators (like kubernetes, ECS or whatever that will recognize that the application didn't start and will try to retrigger the start again, again, and again till the database will be ready)?
This is my recommendation in general.
Now, assuming find answers to all these questions and still, want to proceed with this path:
Spring Boot by itself works like this when it comes to flyway integration:
If the relevant classes (Flyway class) exist on classpath and spring.flyway.enabled=true then the bean of flyway starts and spring boot does its magic.
Technically the relevant auto configuration can be found in class org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration (org.springframework.boot:spring-boot-autoconfigure module)
I think the way to go is to disable flyway, and given that fact that beans like DataSource are available (somehow) - create a Flyway Bean by yourself and trigger the migration in some kind of loop in the background that will exit only if the migration actually succeeds (or already applied)

Fail application startup in Spring Boot in case some property is not valid

I am facing the problem of finding the best place to put some handling where I can check some of the properties in application.yml and fail app startup of Spring Boot app if they are invalid.
The main point is to find the first place where I can check these properties without running the entire app and fail in the end.
I tried:
#EventListener, but here I was able only to trigger events when the app was started.
Throwing an exception in #PostConstruct in one of my classes with #Configuration. I like this one, but it looks like a messy one.
Maybe there are better ways?
#EventListener, but here I was able only to trigger events when the
app was started
There are many different type of events and where you hook in to the startup process depends on the type of event that you listen for. In your case, consider listening for an ApplicationEnvironmentPreparedEvent if you want to check properties as soon as they are available.

How to set up a Spring Context to recover / handle temporary resource failure

Spring is cool when it works. But I am having trouble understanding the best way to approach intermittent failure/retry issues for singletons wired up.
Let me give you two concrete examples:
SessionFactory being wired up
Hashicorp Vault being wired up
In both cases we have a remote server, that yes is fairly reliable, but if it happens to hiccup during initialization of a particular container class (say one that holds some Vault secrets or a SessionFactory), then what can one do to have that retried?
Spring Vault does not provide a retry mechanism. You could hook into ClientRequestFactory with a RetryTemplate using Spring Retry.
Retrying is a form of compensation. In this case (container does not boot properly/isn't healthy at the time of the first request), it looks like you'd be lacking a proper orchestration of startup and health checks. You're assuming the Vault service is healthy/started while your application start but that's not the case.
Retrying will help to some extent but it isn't a solution, it's a patch.

On-the-fly DB reconfiguration in Spring Boot application

I have quite a complex Spring Boot application (including Spring MVC and Security), which among other things requires a database configuration (url, username and password). The requirement is to let end-user configure the DB with the help of the application itself, like the following:
User starts the application, which has no DB configuration yet
Application notices the absence of DB configuration and presents user with configuration screen
User enters url and credentials
Application starts using this DB
The obvious problem is that I cannot create any beans that require a DataSource which requires DB configuration until that configuration is known.
Is there any way to postpone the initialisation of the majority of the application's beans until first configuration step is performed?
-- Update --
Several of application's beans initialise their state from the DB in their #PostConsutrct methods. So I either need to really delay their creation or have a method of refreshing (potentially) all beans in the application context after configuration is provided.
I suggest you could think about having another module/program or a simple script that would ask to provide all details like database etc, store this information to your application.properties file (may be useful re externalized configuration Spring boot external configuration) and then launch your main program with already available information on datasource. This might be a bit easier approach.
As you probably have expected, you need an instance of javax.sql.DataSource at the time when the Spring Application Context is created.
I suggest you subclass Spring's org.springframework.jdbc.datasource.DelegatingDataSource and override afterPropertiesSet with an empty method (the default implementation throws an error if you haven't supplied a datasource). When the user supplies the details you need to select the db, you can inject the final datasource at a later time into DelegatingDataSource.
Source: https://github.com/spring-projects/spring-framework/blob/master/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DelegatingDataSource.java

How to update configuration of SpringBoot application at runtime without reloading whole ApplicationContext

I am trying to figure out how can I dynamically update/reload externalized configuration in a Spring Boot application without restarting the whole application.
Most of the advice involves reloading ApplicationContext after changing the externalized configuration, but that is equivalent to restarting the entire application, so this is not really all that useful.
Reading through SpringBoot reference documentation, I found a chapter 23.7 Typesafe Configuration Properties.
If I understand it correctly, this allows to define simple POJO classes that will hold your application (externalized) configuration values as attributes.
In theory at least, this scheme could be used to bind beans only once to the required configuration POJO and upon configuration change just update the values in the POJO. Components could easily pick up the changes next time they access getters on the POJO...
However, I have yet not managed to figure out how to enable this type of behavior. Is there some glaringly obvious way to dynamically update components annotated with #ConfigurationProperties when relevant configuration has changed?
It sounds like you're looking for #RefreshScope which is provided by Spring Cloud. From the Spring Cloud documentation:
A Spring #Bean that is marked as #RefreshScope will get special treatment when there is a configuration change. This addresses the problem of stateful beans that only get their configuration injected when they are initialized. For instance if a DataSource has open connections when the database URL is changed via the Environment, we probably want the holders of those connections to be able to complete what they are doing. Then the next time someone borrows a connection from the pool he gets one with the new URL.

Categories

Resources