Best way to run exit logic on accidental pod shutdown - java

I am working on a spring boot application and we deploy through kubernetes. My requirement is to run some logic in case the pod crashes or pod gets removed or pod is intentionally shut down. Currently I am using #PreDestroy to run my logics on exit.
#Component
public class EngineShutDownHook{
private static final Logger LOGGER = LoggerFactory.getLogger(EngineShutDownHook.class);
#PreDestroy
public void onExit() {
LOGGER.info("Shutting engine.");
System.out.println(" engine is stopping.");
}
}
However I am not sure whether this code will run on all possible exit scenarios. I have also learnt about spring's ExitCodeGenerator. Can you please suggest which is the best way to achieve this ?

Use Container Lifecycle Hooks of K8s
PreStop: This hook is called immediately before a container is terminated due to an API request or management event such as liveness probe failure, preemption, resource contention and others.

Related

Monitoring Health of a Non web spring boot application

I have a Kafka consumer built using spring boot and spring-kafka. It is not a Web Application (only spring-boot-starter dependency) and hence there is no port that is exposed by the application. And I donot want to expose a port just for the sake of health checks.
This kafka consumer application is being packaged as a docker image. The CI/CD pipeline has a stage that verifies if the container is up and the service is started. One option I thought was to check for an active java process that uses the service jar file.
ps aux | grep java ...
But the catch here is that a Kafka consumer can keep running for a while if the Kafka broker is not up and eventually stop with errors. So, using the process based approach is not reliable always.
Are there any other alternative options to find out if the application is up and running fine, given that the application is a standalone non-web app?
you need to schedule a job in the spring boot application that checks whatever needs to be checked
and write the health check result to a file in the container
you can have a cronjob on container level to check output of the spring
application in the file and make a final decision about the health status of the container
Popular way for checking application's health is using Spring Boot actuator module it checks different aspects of application, It seems that you should use this module and implement custom end point for checking your application health:
Health Indicators in Spring Boot
I have not any ready source code for calling actuator methods manually but you can try this:
Define a command line argument for running actuator health check.
Disable actuator end points:
management.endpoints.enabled-by-default=false
Call actuator health check:
#Autowired
private HealthEndpoint healthEndpoint;
public Health getAlive() {
return healthEndpoint.health();
}
Parse returned Health object and print a string in command line that indicates health status of application.
Grab the printed health status string by grep command.
As outlined in the Spring Boot reference documentation, you can use the built-in liveness and readiness events.
You could add a custom listener for readiness state events to your application. As soon as your application is ready (after startup), you could create a file (and write stuff to it).
#Component
public class MyReadinessStateExporter {
#EventListener
public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
switch (event.getState()) {
case ACCEPTING_TRAFFIC:
// create file /tmp/healthy
break;
case REFUSING_TRAFFIC:
// remove file /tmp/healthy
break;
}
}
}
As explained in the same section, you can publish an AvailabilityChangeEvent from any component - the exporter will delete the file and let other systems know that it's not healthy.

Standard way to run a Java program continously

What is standard(industry standard) way to keep a Java program running continuously.
Use case(Realtime processing):
A continuous running Kafka producer
A continuous running Kafka consumer
A continuous running service to process a stream of objects
Found few questions in Stackoverflow, for example:
https://stackoverflow.com/a/29930409/2653389
But my question is specific to what is the industry standard to achieve this .
First of all, there is no specified standard.
Possible options:
Java EE WEB application
Spring WEB application
Application with Spring-kafka (#KafkaListener)
Kafka producer will potentially accept some commands. In real-life scenario I worked with applications which runs continuously with listeners, receiving requests they triggered some jobs, batches and etc.
It could be achieved using, for example:
Web-server accepting HTTP requests
Standalone Spring application with #KafkaListener
Consumer could be a spring application with #KafkaListener.
#KafkaListener(topics = "${some.topic}")
public void accept(Message message) {
// process
}
Spring application with #KafkaListener will run infinitely by default. The listener containers created for #KafkaListener annotations are registered with an infrastructure bean of type KafkaListenerEndpointRegistry. This bean manages the containers' lifecycles; it will auto-start any containers that have autoStartup set to true. KafkaMessageListenerContainer uses TaskExecutor for performing main KafkaConsumer loop.
Documentation for more information.
If you decide to go without any frameworks and application servers, the possible solution is to create listener in separate thread:
public class ConsumerListener implements Runnable {
private final Consumer<String, String> consumer = new KafkaConsumer<>(properties);
#Override
public void run() {
try {
consumer.subscribe(topics);
while (true) {
// consume
}
}
} finally {
consumer.close();
}
}
}
When you start your program like "java jar" it will work until you didn't stop it. But that is OK for simple personal usage and testing of your code.
Also in UNIX system exist the app called "screen", you can run you java jar as a daemon.
The industry standard is application servers. From simple Jetty to enterprise WebSphere or Wildfly(ex. JBoss). The application servers allows you to run application continiously, communicate with front-end if neccassary and so on.

Close spring on initialization

So I have a Spring app running on Tomcat. While deploying initialization I sometimes may run into some errors (i.e. that some JDNI value is not found or that the app is not able to connect to some service). So when this happen I throw and exception and catch it in the #Configuration file. In the catch block I try to close the app with a System.exit(-1). But it doesn't seem to be the right way to do it. Cause Intellij is no capable or turning off the server, I even have seen that resources are not released till server is OFF.
I have also tried:
#Autowired
public ApplicationContext application context
#Bean
public IServerDataCache serverDataCache() {
try {
return new ServerDataCache(args);
} catch(InitializationError initializationError) {
log.error("Unable to load configuration for Server Data Cache. Closing application.");
System.exit(1); OR SpringApplication.exit(applicationContext)
}
return null;
}
Both System.exit(1); OR SpringApplication.exit(applicationContext) seem to have the same effect. Any idea of a better way to enforce application finalization.
BTW it is a spring boot application.
Just let your #Bean method throw the exception. It will be caught by the container and it'll then take care of tidying things up.
Although Andy Wilkinson's answer is correct, I'd just like to add that, since you're running your application on Tomcat (and not an embedded Tomcat), the Tomcat server doesn't shutdown when the application fails to start.
This happens by design, since Tomcat is, like all JavaEE containers, meant to run several applications at once.
If you want the whole process to stop when the application fails, you need to switch to using an embedded container.

registerShutdownHook() vs Closing an application vs. Application crash? [duplicate]

I am studying for the Spring Core certification and I have some dount about on this question finded into the provided study material:
What is the preferred way to close an application context?
I know that if I have something like this:
ConfigurableApplicationContext context = …
// Destroy the application
context.close();
by the use of the close() method on the context objet the ApplicationContext is closed and the application is destroyed.
But I think that this is not the best way that I have to do it.
Reading the official documentation I find that I can also do something like this:
context.registerShutdownHook();
that register a Shutdown Hook with the JVM so it is the JVM that will trigger Spring's close phase before JVM exits. So on JVM exit, Spring's close phase will execute.
On the documentation I can read that: usually not possible to call context.close() because many applications (web applications) run indefinitely But what exactly means this last assertion? why web application run indefinitely?
So my questions are:
Can I use this second way to close an application context also with not web application?
Is it prefered respect the context.close()?
Tnx
As you are aware that ContextLoaderListener is the one that takes care of initializing and destroying your ApplicationContext, when you shutdown your server, that ContextLoaderListener's contextDestroyed method is invoked.
public void contextDestroyed(ServletContextEvent event){
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
In that closeWebApplicationContext, they actually call the close method on ApplicationContext like this
if ((this.context instanceof ConfigurableWebApplicationContext)) {
((ConfigurableWebApplicationContext)this.context).close();
}
This is straight from spring-web-4.1.5.jar. As it is evident from here, they use close to destroy ApplicationContext in web applications.
But registerShutdownHook is used to explicitly shut down IoC container in non-web applications something like a standalone desktop application, specially when you're creating the ApplicationContext manually from ClassPathXmlApplicationContext (or) FileSystemXmlApplicationContext (or) some other types.
This is done to release all resources used by your spring application and to call destroy method on your spring beans if any.
On the documentation I can read that: usually not possible to call context.close() because many applications (web applications) run indefinitely But what exactly means this last assertion? why web application run indefinitely?
A web application will run as long as the application server that deploys it runs. It is up to the application server (and not to you) to correctly start and stop your application. This means that when the application server is stopped, the servlet context is destroyed. In a Spring application, the ContextLoaderListener class registered in web.xml listens to this event (context destroyed) to properly close the Spring context.
When using Spring outside of an application server (like a standalone application), it is up to you to correctly stop the Spring context. As you said, this can be done by explicitly calling context.close() or registering a shutdown hook (context.registerShutdownHook()) that makes this call for you.
From https://stackoverflow.com/a/42018369:
The ApplicationContext class doesn't define either of these methods as a part of its interface, but the ConfigurableApplicationContext does define both of these.
From the JavaDoc:
close() -- Close this application context, destroying all beans in its bean factory.
registerShutdownHook() -- Register a shutdown hook with the JVM runtime, closing this context on JVM shutdown unless it has already been closed at that time.
Basically, AbstractApplicationContext#close() will close, or shutdown, the ApplicationContext at the time it is invoked, while AbstractApplicationContext#registerShutdownHook() will close, or shutdown, the ApplicationContext at a later time when the JVM is shutting down for whatever reason. This will be achieved by utilizing the JVM shutdown hook functionality.
In either case, the actual closing is done by the doClose() method.
If you are curious about why your outputs look so similar, it is because they are effectively doing the same thing, whether you call close() or registerShutdownHook() at line 3 of you example. close() will shutdown right away, and registerShutdownHook() will shutdown just before the JVM will exit, which is pretty much as soon as the method is done being invoked, because it is the last line of code!

How to reliably kill #Scheduled threads across servers?

I'm building a plugin that is implemented as a Spring MVC application. This plugin is deployed on 3 - 6 tomcat servers via a gui on one of the servers. Each of the instances of the plugin has an #Scheduled method to collect information on the server and store it in a central database.
My issue is that the gui interface for uninstalling the plugin leaves some of the #Scheduled threads running.
For example, I have an environment that has servers 1 - 3. I install and enable the plugin via the gui on server 1. There are now 3 instances of the application running #Scheduled threads on servers 1 - 3. If I go back to server 1 and uninstall the plugin, the thread is reliably killed on server 1 but not servers 2 or 3.
I've implemented the following but the behavior persists:
#Component
public class ContextClosedListener implements ApplicationListener<ContextClosedEvent> {
#Autowired
ThreadPoolTaskExecutor executor;
#Autowired
ThreadPoolTaskScheduler scheduler;
public void onApplicationEvent(ContextClosedEvent event) {
scheduler.shutdown();
executor.shutdown();
}
}
Additionally, I've thought of implementing this as a context listener rather than an #Scheduled method but I'd rather stick to Spring for maintenance and extensibility reasons.
How can I reliably kill threads in an environment like this?
A couple thoughts I have. ThreadPoolTaskExecutor has a method setThreadNamePrefix, which allows you to set the prefix of the thread. You could set the prefix to something unique, then find and kill those threads at runtime. You can also set the thread group using the setThreadGroup method on the same object, then just stop the threads in the threadgroup.
The better, and safer, solution would be to create a break-out method in your scheduled jobs. This is the prefered method to stopping a Thread instead of the old "shot it in the head" method of calling Thread.stop(). You could get reference to those Runnables either by setting a common prefix or by using the thread group as described above.
The next question is: how do you stop the threads easily? For that, it would depend on how your appliation is implemented. Since I deal mainly with Spring MVC apps, my first solution would be to write a Controller to handle admin tasks. If this was JBoss, or some other large app server that had JMX (Tomcat can be configured to provide JMX I believe, but I don't think its configured out of the box that way), I might write a JMX-enabled bean to allow me to stop the threads via the app servers console. Basically, give your self a method to trigger the stopping of the threads.

Categories

Resources