Using Spring Boot 2.0.0.RELEASE on Google Appengine Standard. Using autoscaling but trying to get some control about creation/destruction of the instances. Need to be able to do some cleanup and would like to log those events.
Any methods in Spring Boot like #Predestroy or ContextClosedEvent don't seem to work on GAE.
According to the documention, it should be possible to detect shutdown of an instance by adding a shutdown hook.
Documentation LifecycleManager.ShutdownHook.
Have tried to put it in several places without success.
Example as a #Bean:
#Bean
public LifecycleManager lifecycleManager() {
LifecycleManager lifecycle_manager = LifecycleManager.getInstance();
lifecycle_manager.setShutdownHook(new ShutdownHook() {
public void shutdown() {
LifecycleManager.getInstance().interruptAllRequests();
log.error("Shutdown " + getClassSimpleName() + ".");
}
});
log.warn("Created shutdown hook.");
return lifecycle_manager;
}
Shutdown hook is properly installed, but doesn't get fired when the instance goes down.
As you can read in the Google Issue Tracker:
Shutdown hooks only work for manual scaled instances on the standard runtime (...).
The shutdown hooks simply don't work on automatic and basic scaling.
Related
I have a Spring Boot application that starts listening on Azure IOT Hub at application start. It is done this way:
#EventListener
public void subscribeEventMessages(ContextRefreshedEvent event) {
client
.receive(false) // set this to false to read only the newly available events
.subscribe(this::hubAllEventsCallback);
}
My problem is, that this uses ContextRefreshedEvent but in fact i only want to start it once on application start.
I also checked other methods how start something at the beginning, like CommandLineRunner.
On the other hand if implementing listeners for more standard stuff like JMS there are specific Annotations like #JmsListener or providing Beans of specific Types.
My question is: Can i leverage some of these more message(subscribe) related mechanisms to start my method?
If we don't want our #EventListener to listen on "context refresh" but only on "context start", please (try) replace:
ContextRefreshEvent
with ContextStartEvent
...which is "sibling class" with exactly this semantical difference.
I have a Spring boot application based on CommandLineRunner, when it starts it does some calculations, sends the metrics to Prometheus and shuts down.
I am using Prometheus Push Gateway with Micrometer, mainly based on this tutorial:
https://luramarchanjo.tech/2020/01/05/spring-boot-2.2-and-prometheus-pushgateway-with-micrometer.html
This works fine if I leave the application running however with my particular Spring boot application, it looses the metrics sent just before the shutdown.
I have had similar issue with CloudWatch however it was clear with the Registry implementation CloudWatchMeterRegistry, that it starts a thread in the background and it uses the property cloudwatch.step to schedule the dispatch of the collected metrics. I am struggling to see how PrometheusMeterRegistry is working and not sending the metrics before the application shutsdown.
I have tried to add meterRegistry.close(); just before the shutdown, however it still has the same issue!
After some investigation resolved this by calling the shutdown() method on PrometheusPushGatewayManager.
#SpringBootApplication
public class SpringBootConsoleApplication implements CommandLineRunner {
#Autowired
PrometheusPushGatewayManager prometheusPushGatewayManager;
#PreDestroy
public void onExit() {
System.out.println("Exiting..");
prometheusPushGatewayManager.shutdown();
}
...
And add following in the application.properties:
management.metrics.export.prometheus.pushgateway.shutdown-operation=PUSH
I implemented a custom HealthIndicator for our application, which is working fine.
I noticed that when I run the application through my IDE (tested with both IntelliJ and Eclipse), the HealthIndicator.health() method is invoked during startup.
However, when I run the application by using the JAR file itself, the HealthIndicator.health() method is not invoked during startup of the application.
Why is the HealthIndicator.health() method not invoked during startup when I run it as a JAR file, and shouldn't it behave similarly as when running it through the IDE?
This is actually not really a bug, but a side effect caused by your IDE. You should be aware that Actuator endpoints are not only exposed over HTTP, but also over JMX. If you take a look at the documentation, you'll also see that the health endpoint is enabled by default on both HTTP and JMX.
Additionally, most IDEs, including IntelliJ and Eclipse, will enable a JMX agent when running the application through the IDE itself. This means that when the application is started, a JMX connection is made, which will in turn trigger the custom health indicator.
You can verify this quite easily, for example let's assume the following health indicator:
#Bean
public HealthIndicator alwaysUpHealthIndicator() {
return () -> {
log.info("Indicator invoked");
return Health.up().withDetail("Foo", "Bar").build();
};
}
If you change your IntelliJ run configuration and disable Enable JMX agent, you'll notice that the message no longer appears in the log.
Likewise, if you disable the health JMX endpoint, you'll also notice that you won't get the additional message within the logs:
management.endpoints.jmx.exposure.exclude=health
This means that you shouldn't rely on the HealthIndicator being executed during the startup of your application. If you have code that should be executed when your application is starting up, consider using an ApplicationRunner or CommandLineRunner bean. For example:
#Bean
public ApplicationRunner applicationRunner() {
return args -> log.info("This will be invoked on startup");
}
I can't answer directly the question, but it looks like there is no real question here, if its a bug - submit a bug to spring boot team. Otherwise its just a statement that I fully agree with.
Either HelathIndicator health() method should be executed in both ways or none at all.
What you're describing sounds more like a weird bug, here is a dirty way to check what happens (remove it or course in production):
Inside the health method of the health indicator obtain a stack trace and print it on console.
Analyze the stack trace and check that its not a result of some /health invocation through the HTTP (for example, maybe your IDE is configured to automatically call actuator's health upon start, who knows)
I'm trying to make a command framework for a Discord Bot using Spring Boot with Kotlin. I got it working perfecly with Javacord but recently I decided to switch to JDA and I've hit a snag. The command framework I'm making also relays all Discord events to the Spring Event system and what I'm currently doing is grabbing the generic event listener (https://ci.dv8tion.net/job/JDA/javadoc/net/dv8tion/jda/core/hooks/EventListener.html) and dispatching everything to Spring, using an autowired ApplicationEventPublisher. However, the spring app seems to hang on that line, and after debugging it with some breakpoints it seems that it gets stuck on this particular line (https://github.com/spring-projects/spring-framework/blob/master/spring-context/src/main/java/org/springframework/context/event/AbstractApplicationEventMulticaster.java#L190). Any idea why this is happening? I've seen this (https://github.com/spring-projects/spring-framework/issues/20904) but I'm not sure what to do...
SpringGenericEventPublisher.kt
#Component
class SpringGenericEventPublisher : EventListener {
#Autowired
private lateinit var context: ApplicationEventPublisher
override fun onEvent(event: Event) = context.publishEvent(event)
}
BotConfiguration.kt (where I have the bean that builds the JDA instance)
#Bean
fun bot(config: BotProperties): Bot = JDABuilder() // [Bot] is a typealias for [JDA]
//.setCallbackPool(Executors.newSingleThreadExecutor()) // I've tried this because of the issue I linked above, but I got the same result
.setToken(config.token)
.addEventListener(springGenericEventPublisher)
.build()
Then I have a simple listener just to test
#Component
class FooComponent {
#EventListener(Event::class)
fun onFoo(event: Event) {
println("Reached `onFoo`")
}
}
Any ideas?
Thanks in advance
PS: I should add that I'm also using Spring Data Redis and Spring Data MongoDB and that both fire up with success before that and that the command registry should start after that, just doesn't. The JDA instance logs in perfectly, since if I just print something to the screen instead of publishing the event on SpingGenericEventPublisher it will succeed.
I am working on a standalone application using Spring/JPA and I am trying to release properly the database resources used.
In a Web application using tomcat for example, we shutdown the server, and this way, we let Tomcat manage the resources.
But as I am in a standalone app, I have to take care about this, I use Runtime.getRuntime().addShutdownHook to "catch" the shutdown event and call ((ClassPathXmlApplicationContext) context).close();, something like this:
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
((ClassPathXmlApplicationContext) context).close();
}
It works but with an exception in the stacktrace if a thread was using a connection.
I am wondering if there is another option? Maybe getting a list of open transactions and force them to rollback?
I believe that you would need to implement something like this and inside your destroy method, you would retrieve your datasource and call a close method or something similar. I'm also assuming you have a few things to do when you shutdown your application.
I can't quite help with the right method name as I don't know what you are using for your datasource.