The Spring documentation states the following:

"An application is considered ready as soon as application and command-line runners have been called, see Spring Boot application lifecycle and related Application Events." (https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.spring-application.application-availability.readiness)

It also states the following:

"Tasks expected to run during startup should be executed by CommandLineRunner and ApplicationRunner components instead of using Spring component lifecycle callbacks such as @PostConstruct. "

I think what is missing here is the fact that you cannot use CommandLineRunners or ApplicationRunners if you want to have some code executed and finished BEFORE the ApplicationReadyEvent is fired and BEFORE the application accepts network requests.

It look me a while to find out that I can achieve what I want using a SmartInitializingSingleton. But it was a quite long journey to find that one out.

I think the existence of SmartInitializingSingleton and its purpose should be mentioned next to the description of the Readiness state (https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.spring-application.application-availability.readiness), so that other people don't fall into that trap.

PS: This is the discussion that caused this issue: https://stackoverflow.com/questions/77968217/spring-boot-accepts-network-requests-before-applicationrunners-are-done/77968634#77968634

Comment From: bclozel

I think that this is the expected behavior here.

I think what is missing here is the fact that you cannot use CommandLineRunners or ApplicationRunners if you want to have some code executed and finished BEFORE the ApplicationReadyEvent is fired and BEFORE the application accepts network requests.

I think there is a misunderstanding here. The difference between liveness and readiness is about knowing whether the application is live and if it can receive traffic. If too much work happens before the application context starts and the web server accepts connections, then the platform is likely to kill the application instance because it does not consider it live. The goal here is to start the application as soon as possible to have the liveness endpoint available, and then perform startup tasks while the readiness endpoint states that the application is not accepting traffic yet.

The application indeed accepts network requests if you try it, but the readiness endpoint states otherwise while the runners are executed. You can see the steps in action in the source code here.

I don't think we should mention SmartInitializingSingleton in the docs, since this still happens during the application context setup and will delay the application responding on its liveness endpoint.

I did find an issue in our documentation on the lifecycle and probes states section: "Refuses requests" is a bit too strong, as the server technically accepts requests but tells the platform that it should not send requests its way.

With that in mind, do you see possible improvements in our documentation? Does this clear things up?

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: Walnussbaer

I think that this is the expected behavior here.

I think what is missing here is the fact that you cannot use CommandLineRunners or ApplicationRunners if you want to have some code executed and finished BEFORE the ApplicationReadyEvent is fired and BEFORE the application accepts network requests.

I think there is a misunderstanding here. The difference between liveness and readiness is about knowing whether the application is live and if it can receive traffic. If too much work happens before the application context starts and the web server accepts connections, then the platform is likely to kill the application instance because it does not consider it live. The goal here is to start the application as soon as possible to have the liveness endpoint available, and then perform startup tasks while the readiness endpoint states that the application is not accepting traffic yet.

The application indeed accepts network requests if you try it, but the readiness endpoint states otherwise while the runners are executed. You can see the steps in action in the source code here.

I don't think we should mention SmartInitializingSingleton in the docs, since this still happens during the application context setup and will delay the application responding on its liveness endpoint.

I did find an issue in our documentation on the lifecycle and probes states section: "Refuses requests" is a bit too strong, as the server technically accepts requests but tells the platform that it should not send requests its way.

With that in mind, do you see possible improvements in our documentation? Does this clear things up?

Ok, then let me elaborate what I want to achieve:

I need code to be executed before the application can be considered to be ready. In my case, the completion of this code needs to be awaited.

The thing is, even if the readiness endpoint returns false while the runners are running, I won't be able to control the behaviour of the client of my API. If the client calls the HTTP API of the spring boot app, I will get an - possibly false - answer. This is bad in my opinion. How shall It know that the app is not ready yet if the HTTP API already answers requests? So there might be a business requirement that the application executes some code BEFORE it actually answers any requests.

So what could be done to improve the documentation: next to the explanation of the application's readiness state (here https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.spring-application.application-availability.readiness or here: https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.spring-application.application-events-and-listeners) there should be a link to parts of the documentation that explain how to hook into that lifecycle to be able to run and await code that is required BEFORE the application can be considered ready. Such as the usage of the SmartInitializingSingleton

Comment From: bclozel

Thanks for the update.

Unfortunately, this is a bit of a chicken and egg problem: the platform cannot know whether an application is ready unless it's capable of communicating with it over HTTP - and we can't start the connectors before the application context and its beans are somewhat ready. Now I would argue that it's the job of the platform (usually load balancers) to not direct traffic to the application until the instance is marked as ready.

If your platform does not support this feature I understand the need for SmartInitializingSingleton, but I don't think we should document that as this will be a liveness check problem for most platforms out there and goes against best practices in that domain.

I'm closing this issue as a result. Thanks!

Comment From: Walnussbaer

Thanks for the update.

Unfortunately, this is a bit of a chicken and egg problem: the platform cannot know whether an application is ready unless it's capable of communicating with it over HTTP - and we can't start the connectors before the application context and its beans are somewhat ready. Now I would argue that it's the job of the platform (usually load balancers) to not direct traffic to the application until the instance is marked as ready.

If your platform does not support this feature I understand the need for SmartInitializingSingleton, but I don't think we should document that as this will be a liveness check problem for most platforms out there and goes against best practices in that domain.

I'm closing this issue as a result. Thanks!

I see your point, thanks for taking the time in explaining to me why this is not a problem for most platforms! I will keep that in mind.