Stop Spring Boot on thread error - java

I have this configuration using Spring Boot:
#Bean
public TaskExecutor a() {
return new SimpleAsyncTaskExecutor();
}
#Bean
public CommandLineRunner b() {
return (String... args) -> {
RunnableTask task = SomeRunnableTask();
a().execute(task);
};
}
When that thread stops (for any reason) I want to shut down the Spring Boot application.
The thread is a long running process connecting to a database, webservice, socket... So it's quite likely that at some point it'll fail.
What's the right way of shutting down Spring Boot when a thread stops? Should I not be using SimpleAsyncTaskExecutor from Spring?
Thanks!

Spring Boot has a ShutdownEndpoint which
Allows the application to be gracefully shutdown (not enabled by default).
You have to take a look on it:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500L); // For the response to be sent back to the requester
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
ShutdownEndpoint.this.context.close(); // The ConfigurableApplicationContext
}
});
thread.setContextClassLoader(getClass().getClassLoader());
thread.start();

Related

How to run #PostConstruct non-blocking in Spring?

#PostConstruct
public void performStateChecks() {
throw new RuntimeException("test");
}
If I start a spring application with code above, it will prevent the application to start.
What I'm looking for is to execute a method directly after startup, but async. Means, it should not delay the startup, and it should not prevent the application to run even on failure.
How can I make the initialization async?
You can use EventListener instead of PostConstruct, it supports #Async:
#Service
public class MyService {
#Async
#EventListener(ApplicationStartedEvent.class)
public void performStateChecks() {
throw new RuntimeException("test");
}
}
Don't forget enable async support by #EnableAsync annotation
You can also use some other event, see inheritors of SpringApplicationEvent class
The easiest way I can see is by using EventListeners and async task executors.
Adding this code snippet would do the work:
#Component
public class AsyncStartupRunner {
#Bean(name = "applicationEventMulticaster")
public ApplicationEventMulticaster simpleApplicationEventMulticaster() {
SimpleApplicationEventMulticaster eventMulticaster =
new SimpleApplicationEventMulticaster();
eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
return eventMulticaster;
}
#EventListener(ApplicationReadyEvent.class)
public void executeAfterStartup() {
throw new RuntimeException("Oops");
}
}
There are multiple ways this can be done.
First, simple one-liner solution is to create and start a new thread;
#PostConstruct
public void performStateChecks() {
new Thread(() -> { throw new RuntimeException("test"); }).start();
}
The thrown exception only interrupts the separate thread and doesn't block or prevent the application startup. This is useful if you are not interested in result or outcome of the task. Note this is not recommended as it starts separate thread outside spring managed context.
Second is to use executor service and submit a task to it. Spring provides a default ThreadPoolTaskExecutor which can be used to submit the tasks. This will allow you to have access to the future object of the task and do something with it later on;
private final ThreadPoolTaskExecutor executor; // inject via constructor
#PostConstruct
public void performStateChecks() {
Future<?> future = executor.submit(() -> {
throw new RuntimeException("test");
});
// do something with the future later on
}
If you have multiple such methods and requirements for various services/classes etc then create a new AsyncService class to do the actual work and annotate those methods with #Async. inject the AsyncService wherever you need via constructor and then call the required method;
#EnableAsync
#Component
public class AsyncService {
#Async
public void doActualTest() {
throw new RuntimeException("test");
}
}
Then use it like this;
private final AsyncService asyncService; // make sure to inject this via constructor
#PostConstruct
public void performStateChecks() {
asyncService.doActualTest();
}
You can remove #PostConstruct from your method and let that method be a normal method. You can then manualy invoke it when the ApplicatioinContext is already loaded and the application has already started.
#SpringBootApplication
public class ServiceLauncher {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplication(ServiceLauncher.class).run(args);
try {
context.getBean(YourBean.class).performStateChecks(); // <-- this will run only after context initialization finishes
} catch (Exception e) {
//catch any exception here so it does not go down
}
}
}
}

Spring boot restarts the application after job completion [duplicate]

My Spring Boot application is not a web server, but it's a server using custom protocol (using Camel in this case).
But Spring Boot immediately stops (gracefully) after started. How do I prevent this?
I'd like the app to stop if Ctrl+C or programmatically.
#CompileStatic
#Configuration
class CamelConfig {
#Bean
CamelContextFactoryBean camelContext() {
final camelContextFactory = new CamelContextFactoryBean()
camelContextFactory.id = 'camelContext'
camelContextFactory
}
}
I found the solution, using org.springframework.boot.CommandLineRunner + Thread.currentThread().join(), e.g.:
(note: code below is in Groovy, not Java)
package id.ac.itb.lumen.social
import org.slf4j.LoggerFactory
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
#SpringBootApplication
class LumenSocialApplication implements CommandLineRunner {
private static final log = LoggerFactory.getLogger(LumenSocialApplication.class)
static void main(String[] args) {
SpringApplication.run LumenSocialApplication, args
}
#Override
void run(String... args) throws Exception {
log.info('Joining thread, you can press Ctrl+C to shutdown application')
Thread.currentThread().join()
}
}
As of Apache Camel 2.17 there is a cleaner answer. To quote http://camel.apache.org/spring-boot.html:
To keep the main thread blocked so that Camel stays up, either include the spring-boot-starter-web dependency, or add camel.springboot.main-run-controller=true to your application.properties or application.yml file.
You will want the following dependency too:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>2.17.0</version>
</dependency>
Clearly replace <version>2.17.0</version> or use the camel BOM to import dependency-management information for consistency.
An example implementation using a CountDownLatch:
#Bean
public CountDownLatch closeLatch() {
return new CountDownLatch(1);
}
public static void main(String... args) throws InterruptedException {
ApplicationContext ctx = SpringApplication.run(MyApp.class, args);
final CountDownLatch closeLatch = ctx.getBean(CountDownLatch.class);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
closeLatch.countDown();
}
});
closeLatch.await();
}
Now to stop your application, you can look up the process ID and issue a kill command from the console:
kill <PID>
Spring Boot leaves the task of running the application to the protocol around which the application is implemented. See, for example, this guide:
Also required are some housekeeping objects like a CountDownLatch to keep the main thread alive...
So the way of running a Camel service, for example, would to be to run Camel as a standalone application from your main Spring Boot application class.
This is now made even simpler.
Just add camel.springboot.main-run-controller=true to your application.properties
All threads are completed, the program will close automatically.
So, register an empty task with #Scheduled will create a loop thread to prevent shutdown.
file application.yml
spring:
main:
web-application-type: none
file DemoApplication.java
#SpringBootApplication
#EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
file KeepAlive.java
#Component
public class KeepAlive {
private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
#Scheduled(fixedRate = 1 * 1000 * 60) // 1 minute
public void reportCurrentTime() {
log.info("Keepalive at time {}", dateFormat.format(new Date()));
}
}
My project is NON WEB Spirng Boot.
My elegant solution is create a daemon thread by CommandLineRunner.
Then, Application do not shutdown immediately.
#Bean
public CommandLineRunner deQueue() {
return args -> {
Thread daemonThread;
consumer.connect(3);
daemonThread = new Thread(() -> {
try {
consumer.work();
} catch (InterruptedException e) {
logger.info("daemon thread is interrupted", e);
}
});
daemonThread.setDaemon(true);
daemonThread.start();
};
}
To keep the java process alive when not deploying a web application set the webEnvironment property to false like so:
SpringApplication sa = new SpringApplication();
sa.setWebEnvironment(false); //important
ApplicationContext ctx = sa.run(ApplicationMain.class, args);
for springboot app to run continously it has to be run in a container, otherwise it is just like any java app all threads are done it finishes,
you can add
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
and it will turn it into webapp, if not you are responsible keeping it alive in your implementation

how to catch the event of shutting down of tomcat?

What I want is to start a thread every time the tomcat server starts.For this I need to catch the event of shutting down of tomcat.How can I do this?I tried to do it using sessions but sometimes the session even persists after shutting down and restating tomcat?what are my options?
You can try to catch an JVM shutdown event in this way:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("BYE BYE");
}
});
The other option is to implement ServletContextListener by using #WebListener Annotation. No xml configuration is required in this case.
#WebListener
public class MyLifeCycleListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
//TODO ON START
}
public void contextDestroyed(ServletContextEvent event) {
//TODO ON DESTROY
}
}

How does Lifecycle interface work in Spring? What are "top-level singleton beans"?

It is said in Spring javadoc, that "Note that the Lifecycle interface is only supported on top-level singleton beans." Here URL
My LifecycleBeanTest.xml describes bean as follows:
<beans ...>
<bean id="lifecycle" class="tests.LifecycleBean"/>
</beans>
so it looks "topish" and "singletonish" enough.
What does it mean? How to make Spring know about my bean implementing Lifecycle and do something with it?
Suppose my main method looks following in Spring
public static void main(String[] args) {
new ClassPathXmlApplicationContext("/tests/LifecycleBeanTest.xml").close();
}
so, it instantiates context and then closes it immediately.
May I create some bean in my configuration, which delays close() execution until application do all it's works? So that main method thread wait for application termination?
For example, the following bean does not work in way I thought. Neither start() not stop() is called.
package tests;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.Lifecycle;
public class LifecycleBean implements Lifecycle {
private static final Logger log = LoggerFactory.getLogger(LifecycleBean.class);
private final Thread thread = new Thread("Lifecycle") {
{
setDaemon(false);
setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
log.error("Abnormal thread termination", e);
}
});
}
public void run() {
for(int i=0; i<10 && !isInterrupted(); ++i) {
log.info("Hearbeat {}", i);
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
};
};
#Override
public void start() {
log.info("Starting bean");
thread.start();
}
#Override
public void stop() {
log.info("Stopping bean");
thread.interrupt();
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
#Override
public boolean isRunning() {
return thread.isAlive();
}
}
UPDATE 1
I know I can wait for bean in code. It is interesting to hook into Spring itself.
You should use SmartLifecycle instead of Lifecycle. Only the former is working as you expected Lifecycle to work. Make sure you return true in your isRunning() implementation.
I have used SmartLifecycle for asynchronous jobs for which it sounds like designed for. I suppose it will work for you but at the same time you may have a look at ApplicationListener and events like ContextStoppedEvent.
You can examine AbstractApplicationContext.doClose() method and see that no interruption of application context closing has been provided by the Spring developers
protected void doClose() {
boolean actuallyClose;
synchronized (this.activeMonitor) {
actuallyClose = this.active && !this.closed;
this.closed = true;
}
if (actuallyClose) {
if (logger.isInfoEnabled()) {
logger.info("Closing " + this);
}
try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
try {
getLifecycleProcessor().onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
// Close the state of this context itself.
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
onClose();
synchronized (this.activeMonitor) {
this.active = false;
}
}
}
So you can't prevent the application context from closing.
Testing the service with TestContext framework
If you are using Spring test context framework with JUnit, I think you can use it to test services that implement Lifecycle, I used the technique from one of the internal Spring tests
Slightly modified LifecycleBean(I've added waitForTermination() method):
public class LifecycleBean implements Lifecycle {
private static final Logger log = LoggerFactory
.getLogger(LifecycleBean.class);
private final Thread thread = new Thread("Lifecycle") {
{
setDaemon(false);
setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
log.error("Abnormal thread termination", e);
}
});
}
public void run() {
for (int i = 0; i < 10 && !isInterrupted(); ++i) {
log.info("Hearbeat {}", i);
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
};
};
#Override
public void start() {
log.info("Starting bean");
thread.start();
}
#Override
public void stop() {
log.info("Stopping bean");
thread.interrupt();
waitForTermination();
}
#Override
public boolean isRunning() {
return thread.isAlive();
}
public void waitForTermination() {
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
Test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:Test-context.xml")
public class LifecycleBeanTest {
#Autowired
LifecycleBean bean;
Lifecycle appContextLifeCycle;
#Autowired
public void setLifeCycle(ApplicationContext context){
this.appContextLifeCycle = (Lifecycle)context;
}
#Test
public void testLifeCycle(){
//"start" application context
appContextLifeCycle.start();
bean.waitForTermination();
}
}
Test-context.xml content:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="LifecycleBean"/>
</beans>
P.S. starting and stopping the context is not a thing you may want to do many times on the same application context, so you may need to put #DirtiesContextannotation on your test methods for the best results.
Answer to the new version of the question
DefaultLifecycleProcessor uses beanFactory.getBeanNamesForType(Lifecycle.class, false, false); to retrieve the list of the beans implementing Lifecycle
From getBeanNamesForType javadoc:
NOTE: This method introspects top-level beans only. It does
not check nested beans which might match the specified type
as well.
So this method does not list the inner beans (they were called nested when only xml configuration was available - they are declared as nested bean xml elements).
Consider the following example from the documentation
<bean id="outer" class="...">
<!-- Instead of using a reference to target, just use an inner bean -->
<property name="target">
<bean class="com.mycompany.PersonImpl">
<property name="name"><value>Tony</value></property>
<property name="age"><value>51</value></property>
</bean>
</property>
</bean>
Start() and Stop() are merely events that are propagated by the application context they are not connected with lifetime of the application context, for example you can implement a download manager with some service beans - when the user hits "pause" button, you will broadcast the "stop" event, then when the user hits "start" button, you can resume the processing by broadcasting the "start" event. Spring is usable here, because it dispatches events in the proper order.
I never used Lifecycle interface and I am not sure how it is suppose to work. But it looks like simply calling start() on context calls these callbacks:
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("...");
ctx.start();
However typically I use #PostConstruct/#PreDestroy annotations or implement InitializingBean or DisposableBean:
public class LifecycleBean implements InitializingBean, DisposableBean {
#Override
public void afterPropertiesSet() {
//...
}
#Override
public void destroy() {
//...
}
}
Notice I don't call close() on application context. Since you are creating non-daemon thread in LifecycleBean the JVM remains running even when main exits.
When you stop that thread JVM exists but does not close application context properly. Basically last non-daemon thread stops, causing the whole JVM to terminate. Here is a bit hacky workaround - when your background non-daemon thread is about to finish, close the application context explicitly:
public class LifecycleBean implements ApplicationContextAware /* ... */ {
private AbstractApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = (AbstractApplicationContext)applicationContext;
}
public void run() {
for(int i=0; i<10 && !isInterrupted(); ++i) {
log.info("Hearbeat {}", i);
try {
sleep(1000);
} catch (InterruptedException e) {
}
}
applicationContext.close();
}
}
So, finally I foundm that if I:
1) Define my bean as implements Lifecycle
2) Introduce a delay in stop() method like this
#Override
public void stop() {
log.info("Stopping bean");
//thread.interrupt();
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
3) And code context creation as follows:
new ClassPathXmlApplicationContext("/tests/LifecycleBeanTest.xml").stop();
Then I get what I want:
context creation code does not exit until all stops of all Lifecycle beans executed. So, this code works in JUnit tests
What about using SmartLifecycle? Seems like it provides all necessary functionality.
There is method public void stop(Runnable contextStopping) {}.
And you can continue app context closing by executing passed in contextStopping in time you want.
In my environment all works fine even on J-UNIT, of course by running them with SpringJUnit4ClassRunner.

How to shutdown ThreadPoolExecutor in spring bean when tomcat is shutdown?

I create a threadpoolexecutor in a spring bean, so I need to shutdown this executor when tomcat is shutdown.
public class PersistBO implements InitializingBean {
private ThreadPoolExecutor executer;
public void shutdownExecutor() {
executer.shutdown();
}
#Override
public void afterPropertiesSet() throws Exception {
taskQueue = new LinkedBlockingQueue<Runnable>(queueLength);
executer = new ThreadPoolExecutor(minThread, maxThread, threadKeepAliveTime,
TimeUnit.SECONDS, taskQueue, new ThreadPoolExecutor.DiscardOldestPolicy());
}
I have searched solution on google and get a result. That is to add a shutdownhook to java.lang.runtime. However, the java docs says java.lang.Runtime#shutdownHook is called when the last non-daemon thread exits. So it is a dead lock. Is there any solution to shutdown executor in spring bean?
I guess lifecycle of the executor should depend on lifecycle of your application, not Tomcat as a whole. You can stop your application while Tomcat is still running, therefore Runtime.shutdownHook() is not applicable.
Since you already use Spring and its InitializingBean for initialization, you can use DispasableBean to perform cleanup when application context is being closed:
public class PersistBO implements InitializingBean, DisposableBean {
public void destroy() {
shutdownExecutor();
}
...
}
Use the Runtime to add a shutdown hook. Here's a very good tutorial by Heinz Kabutz: http://www.roseindia.net/javatutorials/hooking%20_into_the_shutdown_call.shtml
You can implement your own javax.servlet.ServletContextListener to be notified when your application is being shutdown and shutdown the pool from the listener.
Use the #Predestroy annotation on your shutdown method on the bean. this will result in spring calling this method when context is shutting down
Check if there is some executor service has a thread running in background. you can shutdown an executor by calling executor.shutdownNow().
also see http://taranmeet.com/jvm-not-shutting-down-on-spring-context-close/
Here is how to start and stop a thread in Spring bean.
#PostConstruct
public void init() {
BasicThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern("myspringbean-thread-%d").build();
executorService = Executors.newSingleThreadExecutor(factory);
executorService.execute(new Runnable() {
#Override
public void run() {
try {
// do something
System.out.println("thread started");
} catch (Exception e) {
logger.error("error: ", e);
}
}
});
executorService.shutdown();
}
#PreDestroy
public void beandestroy() {
if(executorService != null){
executorService.shutdownNow();
}
}

Categories