I know this question was asked couple of times but none have provided a correct answer so reposting
I have a Spring4-Jersey webservice that runs inside Tomcat 7.
I am using Spring's ThreadPoolTaskExecutor to process some messages off a queue. I have a bean that uses #Scheduled which submits tasks to the executor every 1000 millis.
However, I have noticed when I shutdown Tomcat, it warns me that it can't shutdown some tasks.
SEVERE: The web application appears to have started a thread named [taskExecutor-9] but has failed to stop it. This is very likely to create a memory leak.
org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
this what I have in code to initialize taskExecutor
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(100);
}
http://docs.spring.io/spring/docs/3.2.0.RC1_to_3.2.0.RC2/changes/docdiffs_org.springframework.scheduling.annotation.html
mentions that spring would take care of the threads that i created; but unfortunately it doesn't seem to be case...
Could someone provide any pointers ??
As its a web-application, you can try something like below;
Your SchedulingConfiguration Class
#Configuration
#EnableScheduling
public class SchedulerConfig implements SchedulingConfigurer {
/* Beans and Other Stuff */
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(workers());
}
#Bean(name = "executorService")
ExecutorService workers() {
return Executors.newScheduledThreadPool(100);
}
}
ShutDown The ExecutorService in ServletContextListener's contextDestroyed method.
#Configuration
public class CustomServletContextListener implements ServletContextListener {
#Autowired
private ExecutorService executorService;
#Override
public void contextInitialized(ServletContextEvent context) {
/* Do stuff If Required */
}
#Override
public void contextDestroyed(ServletContextEvent context) {
executorService.shutdown();
}
}
Worked for me and I use Tomcat8.
Related
I created a SpringBoot 2.4.2 application that has several long running tasks that should not be terminated while they are still running.
I have defined the Scheduler like this:
#Configuration
public class SchedulerConfig implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(10);
scheduler.setThreadNamePrefix("my-scheduled-task-pool ");
scheduler.setAwaitTerminationSeconds(30);
scheduler.setWaitForTasksToCompleteOnShutdown(true);
scheduler.initialize();
taskRegistrar.setTaskScheduler(scheduler);
}
}
Then I have an #Service class in a seperate package that contains a method like this:
#Scheduled(fixedDelay = 5000)
public void myTask() {
someLongRunningTask();
System.out.println("Finished Task")
}
When I terminate the Program by either doing CTRL+C in the Terminal or calling kill -15 {$pid}, spring shuts down before the myTask() method is finished.
Is there a way I can force Spring to always wait for all of my Tasks to finish before Shutting down? I was under the assumption that scheduler.setWaitForTasksToCompleteOnShutdown(true) took care of this.
Thanks a lot for your help
I created a simple spring boot application with scheduled (#Scheduled) task. In that scheduled task, I would like to call async function with #Async, but I can see it still runs on the scheduling thread without switch to another thread. I also tried to customise executor, but no luck. Here are some codes.
I also already enable async in main class
public class scheduledService {
#Scheduled(fixedRateString = "${config.scheduleInterval}")
public void pollDataWithFixSchedule() {
AsyncService service = new AsyncService();
service.asyncCall();
service.asyncCall();
service.asyncCall();
asyncCall();
}
}
public class AsyncService {
#Async()
public void asyncCall(){
System.out.printly("Current thread -- {}",Thread.currentThread().getName()))
Thread.sleep(10000);
}
}
#Bean(name = "MyThreadPoolExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyThreadPoolExecutor-");
executor.initialize();
return executor;
}
#SpringBootApplication
#EnableScheduling
#EnableAsync
public class ScheduledApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(ScheduledApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
}
according to Baeldung:
#Async has two limitations:
it must be applied to public methods only
self-invocation – calling the async method from within the same class – won't work
The reasons are simple – the method needs to be public so that it can be proxied. And self-invocation doesn't work because it bypasses the proxy and calls the underlying method directly.
so you can put your async method in a service and use it from there
you need to autowire AsyncService, do not create new object like
AsyncService service = new AsyncService();
Also, annotate your scheduledService class with #Service or #Component
#Service
public class scheduledService {
#Autowired
private AsyncService service ;
#Scheduled(fixedRateString = "${config.scheduleInterval}")
public void pollDataWithFixSchedule() {
service.asyncCall();
service.asyncCall();
service.asyncCall();
}
}
不要在同一个类中调用异步方法
Do not call asynchronous methods in the same class.
将异步任务单独放到一个类 并且在这个类上加上#Component
Put asynchronous tasks into a single class and add # component to this class
Use #EnableAsync on the top of class where you are creating async bean, not on the ScheduledApplication.
I have a method that will be rarely called. This method collect garbage in db. I don't want to make user to wait for server response so i decided to call this method from new thread from my service layer. i'm using Spring.
Service class:
#Service
#Transactional
public class UploadService {
#Resource(name = "UploadDAO")
private UploadDao uploadDao;
Method that i don't want to wait for
public void collectBlobGarbage(){
Thread th = new Thread(new Runnable() {
#Override
public void run() {
uploadDao.collectBlobGarbage();
}
});
th.start();
}
Is it a good way to do like this?
If you have Spring on your classpath you might as well use #Async
#Async
public CompletableFuture<Void> collectBlobGarbage() throws InterruptedException {
CompletableFuture.completeFuture(uploadDao.collectBlobGarbage());
}
On your main class you need to use #EnableAsync like:
#SpringBootApplication
#EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
And you need an executor bean:
#Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("Stackoverflow-");
executor.initialize();
return executor;
}
I think the provided solution can potentially cause a lot of threads on you server.
As an alternative, you can consider using Executors.newSingleThreadExecutor in such a way that you will get an executor service that is limited only to one thread—so you will never create more than one thread—and that is what you need.
Also as you are using Spring, consider configuring a SingleThreadExecutor instantiation as a separate bean—in such a way that you will be able to change the implementation of ExecutorService in the future.
I have a Spring Boot Application that uses CommandLineRunner and the Spring #Async annotation to run a method asynchronously. It all works fine, but when all of my threads complete, the application just hangs instead of exiting.
Here is a minimal example of what I have in my application:
Application.java:
#SpringBootApplication
#EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
ApplicationStartup.java:
#Component
public class ApplicationStartup implements CommandLineRunner {
private final AsyncService asyncService;
#Inject
public ApplicationStartup(final AsyncService asyncService) {
this.asyncService = asyncService;
}
#Override
public void run(final String... strings) throws Exception {
//my logic is more complicated than this, but this illustrates my point
for (int i = 0; i < 1000; i++) {
asyncService.runAsyncMethod();
}
}
}
AsyncService.java:
#Service
#Transactional
public class AsyncService {
#Async
public void runAsyncMethod() {
//perform call to an API and process results
}
}
ExecutorConfig.java:
#Configuration
public class ExecutorConfig() {
#Bean
public ThreadPoolTaskExecutor asyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(64);
executor.setMaxPoolSize(64);
executor.setQueueCapacity(500);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadNamePrefix("Scrub-");
executor.setKeepAliveSeconds(60);
executor.initialize();
return executor;
}
}
All of my threads make the call to runAsyncMethod() and every method call completes successfully, but then the application just hangs.
I tried changing some of the executor settings around. I didn't have the keepAliveSeconds at first, so I thought adding that would fix it, but it still hung after all threads were complete. I changed corePoolSize to 0, and that made the application exit when it was done, but it only used 1 thread the whole time.
Any ideas as to why the application is not exiting with the configuration above?
You missed to join the asynchronous jobs, that's why the run method exits (far) before all threads complete - and the awkward behavior is "more comprehensible".
According to doc, you could join like:
...
CompletableFuture<Void>[] myJobs = new CompletableFuture<>[N];
...
for (int i = 0; i < N; i++) {
myJobs[i] = asyncService.runAsyncMethod();
}
...
CompletableFuture.allOf(myJobs).join();
And your runAsyncMethod() would need to return a CompletableFuture<Void>. To do so, you can just return CompletableFuture.completedFuture(null);
Even if the marked as correct answer is valid. This is not full answer.
Without #EnableAsync and without WEB environment .web(WebApplicationType.NONE) the spring boot app automatically stop once started(as there is nothing to do/wait). So even if you don't do apringApp.close() in your app but only app.run(commandLine), the .close() method call automatically.
But once you added #EnableAsync - the behavior changes, as there might be async work, so app is not stopped once started. And if there is not stopping code, the app remain working (hangs).
For fixing this you need to do 2 things:
in the run method do wait all async work
implicitly call .close()after app started
Sample:
#EnableAutoConfiguration
#EnableAsync
public static class SpringApp extends SpringApplication {
#Bean
public TaskExecutor taskExecutor () {
return new SimpleAsyncTaskExecutor();
}
#Autowired
private Service service;
#EventListener
public void handleContextRefresh(ContextRefreshedEvent event){
CompletableFuture<Void> aggregateFuture = service.doWork();
// avoid exiting this method before all job complected prevents app from hanging
aggregateFuture.join();
}
}
public static void main(String[] args) {
SpringApplicationBuilder app = new SpringApplicationBuilder(SpringApp.class).web(WebApplicationType.NONE);
app.run()
.close(); // <--- THIS!
}
I am instantiating a ScheduledExecutorService using Spring's ApplicationListener interface as follows:
#Component
public class ExecutorsStart implements ApplicationListener<ContextRefreshedEvent> {
private ScheduledExecutorService executor;
#Autowired
Scheduler scheduler;
#Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
executor = Executors.newSingleThreadScheduledExecutor();
scheduler.init();
int delay = 10;
int period = 60;// repeat every 1 minutes.
executor.scheduleAtFixedRate(scheduler, delay, period, TimeUnit.SECONDS);
}
At the moment, Tomcat won't shut down cleanly when I run, ./shutdown.sh, with message:
The web application [/foo] appears to have started a thread named [pool-1-thread-1] but has failed to stop it
and this seems to be because I have not yet written code to stop the ScheduledExecutorService.
My question is: how should this be done properly in this environment?
I noticed that there exists a ContextStoppedEvent, so, I implemented a listener for it:
#Component
public class ExecutorsStop implements ApplicationListener<ContextStoppedEvent> {
#Autowired
ExecutorsStart executorsStart;
#Override
public void onApplicationEvent(final ContextStoppedEvent event) {
executorsStart.executor.shutdownNow();
}
But it seems that this event handler doesn't get called when Tomcat is shutdown.
Have I implemented this incorrectly, or am I going about this completely the wong way?
You're looking for ContextClosedEvent.
#Component
public class ExecutorsStop implements ApplicationListener<ContextClosedEvent> {
#Autowired
ExecutorsStart executorsStart;
#Override
public void onApplicationEvent(final ContextClosedEvent event) {
System.out.println("Stopped: " + event);
}
}
When the Servlet container shuts down, it calls contextDestroyed(..) on its various ServletContextListener and destroy() on its Servlet instances. The ContextLoaderListener and DispatcherServlet each call close() on their ApplicationContext.