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

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();
}
}

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: Can we have seperate thread pool for each request?

I've implemented asynchronous execution for a method in my application using Spring Boot #Async. I'm having a custom thread pool with 20 thread. In a for loop calling the async method for 30 times.
Each individual request is executing asynchronously but when i made two different requests at the same time to my API from browser, first request is executing and then second. Not both requests executing the same method parallely.
I thought when first request reach the app, it's started executing the async method and since it's being executing for 30 times and my pool is having 20 threads, all threads are busy in executing first request. So even second request came for execution also since the pool of threads busy, the other request is waiting till a thread becomes free in the pool.
Can we have separate thread pool for each individual request. or any way that we can make execution of each request separate independent of other request processing.
Here is my code sample.
#SpringBootApplication
#EnableAsync
public class AppBootStrap
{
public static void main(String[] args)
{
SpringApplication.run(AppBootStrap.class, args);
}
#Bean
public AsyncTaskService asyncTaskService() {
return new AsyncTaskService();
}
#Bean(name="customExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
poolExecutor.setCorePoolSize(10);
poolExecutor.setMaxPoolSize(20);
poolExecutor.setThreadNamePrefix("customPoolExecutor");
poolExecutor.initialize();
return poolExecutor;
}
}
**Controller Class:**
#RestController
public class TaskController
{
#Autowired
private TaskService taskService;
#RequestMapping("/performAction")
public void performAction() {
taskService.performAction();
}
}
**Service class**
#Service
public class TaskService
{
#Autowired
private AsyncTaskService asyncTaskService;
public void performAction()
{
for(int i = 0; i < 30; i++) {
asyncTaskService.greetings(i);
}
}
}
**Async Method Class**
public class AsyncTaskService
{
#Async
public void greetings(Integer i)
{
try
{
Thread.sleep(500 * (i + 10));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("Welcome to Async Service: " + i);
}
}
#Bean(name = "apiTaskExecutor")
public ThreadPoolTaskExecutor apiTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(50);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
#Bean(name = "lruTaskExecutor")
public ThreadPoolTaskExecutor lruTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(100);
executor.setMaxPoolSize(200);
executor.setQueueCapacity(500);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
The Way to do this is to create two Thread different Thread Pools using Different Qualifier names. (As shown above)
#Autowired
#Qualifier("apiTaskExecutor")
private ThreadPoolTaskExecutor apiTaskExecutor;
Then autowire the required pool using the qualifier you have given . You can also use the #Async annotation instead of autowiring . I prefer this way.
If I am not wrong this way of having different thread pools for different Tasks is known as bulkhead pattern.
I think the problem is that the customExecutor bean is a singleton. This means that when the second request tries to use this bean it finds all the threads of the thred pool busy. You can try to make the customExecutor bean non-singleton by using the #Scope("prototype") annotation which will cause a new one to be instantiated whenever a bean of this type is requested.

Stop Spring Boot on thread error

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();

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.

Categories