spring cloud stream destroys The readyness state
Describe the issue Originally invented @philwebb with: https://github.com/spring-projects/spring-boot/issues/7656 The "readiness" framework, that enables to register "ApplicationRunner" to ensure for example a "cache" is loaded before the application is ready to server.
But when spring cloud stream is used following happend:
@org.springframework.boot.SpringApplication#run(java.lang.String...)
refreshContext(context);
--> ScSt wants to create the binder
--> DefaultBinderFactory starts a new inner SpringApplication
--> It run again: SpringApplication#run(java.lang.String...)
--> callRunners(context, applicationArguments); // will not find any "ApplicationRunner", what is correct
--> listeners.running(context); // called and fire the "ReadinessState.ACCEPT". This is the BUG
--> .... spring cloud stream set up its binders ...
callRunners(context, applicationArguments); // will execute the "ApplicationRunner" that is set up my application cache.
listeners.running(context); // The "ReadinessState.ACCEPT" event gets fired that i expect.
To Reproduce Steps to reproduce the behavior:
- Download: readiness.zip
- If you dont like the solace binder replace against what ever you want.
- Run the spring application
- Wait for "BusinessLogic: load my cache from DB" in log
- Open on browser: http://localhost:9007/actuator/health/readinessState Expected: status: "OUT_OF_SERVICE" Current state: status: "OK"
- Wait for "BusinessLogic: cache load complete" in log Expected: status: "OK" Current state: status: "OK"
I read now the history of the code up and down. But dont see a very god straight forward solution.
@philwebb Would it ok for you to:
Hand over here an argument like "--lister=suppress" https://github.com/spring-cloud/spring-cloud-stream/blob/master/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java#L325
To suppress all listeners including: https://github.com/spring-projects/spring-boot/blob/6254ad634ecb0dc73034038f82fcde75fb99117a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java
I would add here: https://github.com/spring-projects/spring-boot/blob/6254ad634ecb0dc73034038f82fcde75fb99117a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java#L449
if (Arrays.asList(args).contains("--lister=suppress")) {
return Collectiosn.emptyList();
}
It is a bit of pain that spring.factories are currently all or nothing. I don't particularly like the idea of using the arguments to suppress the listeners. I'd probably prefer dedicated methods on SpringApplication and SpringApplicationBuilder. Perhaps we should offer some kind of SpringFactoriesFilter interface that can accept or reject specific instances. Feel free to raise an issue on the Spring Boot issue tracker for that if you think it would help.
I think that the new config data api could be used rather than Spring application
Yes please, @spencergibb. If using the config data API lets you get rid of the context hierarchy, that sounds ideal to me. It would also simplify some other problems we've seen in SCS (IIRC) with the logging system when there's a child app with a different lifecycle to its parent.
@spencergibb and I talked about this, so it is on my list of things to do, but will admit, low in priority especially with SCSt plans for 4.0.
@olegz Can you give any release estimations? Or better time ranges? Can i support you some how?