Stop ConcurrentTaskScheduler when spring context closed - java

I am writing a simple spring application with AnnotationConfigApplicationContext. I have a ConcurrentTaskScheduler in my application. What is the best practice for stopping the ConcurrentTaskScheduler when the spring context closed?
Update: The main problem is when Junit close the context in #After annotation all threads will be terminated but when i manually close the context at the end of application, Some threads running by ConcurrentTaskScheduler will continue running.

Let Spring handle the shutdown itself.
Pass a ScheduledExecutorService to your ConcurrentTaskScheduler.
Than add a method with anotation #PreDestroy in which shutdown the ScheduledExecutorService.
#PreDestroy
public void cleanUp() throws InterruptedException {
scheduleExecutorService.shutdown();
try {
scheduleExecutorService.awaitTermination(10000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
scheduleExecutorService.shutdownNow();
throw e;
}
}

What I do in my project is, I save the jobs in the database so I can have a control over it, so in the future I can just grab the information from it and stop.
How to manage/stop spring 4 ConcurrentTaskScheduler

Related

ScheduledExecutorService inside a Spring Bean, not working after a couple of executions

I am trying to schedule a task inside a Spring #Bean which will update the property of the instance returning from Bean.
I am able to run this code, and the executor works fine a couple of times, but after that, it suddenly stops loading.
What exactly is the problem here? Is there a better way to work this out??
#Bean(name="service")
public Service getService(){
Service service = new Service();
ScheduledExecutorService serviceLoader = Executors.newScheduledThreadPool(1);
serviceLoader.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
service.loadAllLiveEvents();
}
}, 0, 1, TimeUnit.HOURS);
return service;
}
The lifecycle of serviceLoader looks weird - it gets initialized right during the method or service, then schedules some work and then service gets returned. What happens to the reference to this pool? when the shutdown can be called?
In addition, the first iteration runs immediately, and this happens when the application context is not ready yet, this can lead to unpredictable results depending on the actual code that runs during the iteration.
I can't say for sure what happens based on this code snippet, but here are some possible solutions:
Use #Scheduled annotation, running scheduled tasks is a bulit-in spring feature. There are a lot of tutorials, here is one of them
If you absolutely have to use the thread pool, I suggest the following configuration:
#Configuration
public class MyConfiguration {
#Bean
public Service service() {
return new Service();
}
#Bean(destroyMethod="shutdownNow") // or shutdown - now spring will close the pool when the app context gets closed
#Qualifier("serviceLoaderPool")
public ScheduledExecutorService serviceLoader() {
return Executors.newScheduledThreadPool(1);
}
#EventListener
public void onAppContextStarted(ApplicationReadyEvent evt) {
ScheduledExecutorService loader =
(ScheduledExecutorService)evt.getApplicationContext().getBean("serviceLoaderPool");
Service service = evt.getApplicationContext.getBean(Service.class);
loader.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
service.loadAllLiveEvents();
}
}, 0, 1, TimeUnit.HOURS);
}
}
With this approach you can be sure that the service will start refreshing when the application context is ready.
The lifecycle of the executor service is well-defined as well, spring manages it as a regular singleton bean, so it won't be GC'ed as long as the application context is up-and-running.
The presence of destroy method guarantees graceful shutdown (again, spring will call it for you).

Spring do on startup ingnoring failures

I need to perform some work when the spring application is ready, something similar to #Scheduled but I want it to perform only once.
I found some ways to do it, such as using #PostConstruct on a bean, using #EventListener or InitializingBean, however, all of these ways does not match my need. If during the execution of this logic something goes wrong, I want to ignore it so the application starts anyway. But using these methods the application crashes.
Of course, I can surround the logic with try-catch and it will work. But, is there any more elegant way?
We faced a similar issue with our microservices , in order to run code just after startup we added a Component.
ApplicationStartup implements ApplicationListener<ApplicationReadyEvent>
Within the application to make a call to the services just after application startup, this worked for us.
#Component
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {
#Autowired
YourService yourService;
#Override
public void onApplicationEvent(final ApplicationReadyEvent event) {
System.out.println("ApplicationReadyEvent: application is up");
try {
// some code to call yourservice with property driven or constant inputs
} catch (Exception e) {
e.printStackTrace();
}
}
}
When you use #PostConstruct for implementing a logic, the application is not ready yet, so it kind of contradicts your requirement. spring initializes the beans one by one (with respect to the dependencies between them.
After all it builds up the application context.
When the application context is fully initialized, spring indeed allows listeners to be run. So The listeners is a way to go - when the listener is invoked the application is ready.
In both cases (PostConstruct, EventListener) as long as you're not using try/catch block the application context will fail, because it waits till all the listeners will be done.
You can use #Async if you don't want the application context to wait for listeners execution. In this case the exception handling will be done by the task executor. See here
Personally I don't see any issue with try/catch approach
You can use #PostConstruct (as you said) but you must wrap your business in try catch and ignore it when it throws an exception.
Sample Code
#PostConstruct
void init() {
try {
//Your business
}
catch (Exception e) {
//Do nothing Or you can just log
}

Spring Boot: How do I know if an Application was interrupted in #PreDestroy Method

I there any way to find out if the #PreDestroy Method in a Spring Boot Application was called because CTRL-C was pressed or kill <PID> was called?
I want to differ from the case that the Application regularly stops. (No Daemon, No Web Server)
Background:
I'm using Spring Boot as an Runner that is started in a Docker Container by a schedule. The App does it work and closes itself. The kill <PID> occurs when docker stop <containerid> is called.
You can write your own aspect to log any #PreDestroy execution
#Aspect
#Component
public class CustomAspect {
#Around("#annotation(javax.annotation.PreDestroy)")
public Object logPreDestroyExecution(ProceedingJoinPoint joinPoint) throws Throwable {
// ...
// get info from joinPoint and log
// ...
return joinPoint.proceed();
}
}
More detailed example: Spring AOP + AspectJ

Shutdown service after the service has done its job

I am creating a service which watch for a file and as soon as file is available it loads it to db. Once this job is done I want to shutdown the app gracefully.
But when I use context.close it throws exception (though the app shuts down) but I want to shut it down without causing any exception.
#profile("non-test")
class Manager implements ApplicationContextAware{
#PostConstruct
public void init()
{
//watch for file and as soon as file is available invokde trigger()
}
public void trigger()
{
//load to db
shutodown()
}
public void shutdown()
{
SpringApplication.exit(context);
}
}
when i call shutdown it throws below exception.
AnnotationConfigApplicationContext has already been closed
I want the app to shutdown gracefully without any exception.
You problem is most probably presence of Spring dependency that makes your app long lived. Such dependency is for example spring-boot-starter-web. This starter includes Servlet container as dependency ans Spring will by default be running forever.
If non of such dependencies is on classpath, your Spring Boot app would shut down automatically (without any special effort to kill it). I would suggest to take a look at some of Spring guides for batch job.

Scheduled method in a standalone application in spring

I have a method which needs to be executed every day at 07:00.
For that matter I created a bean with the method and annotated it with #Scheduled(cron="0 0 7 * * ?").
In this bean I crated a main function - which will initialize the spring context, get the bean and invoke the method ( at least for the first time ), like this:
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(args[0]);
SchedulerService schedulerService = context.getBean(SchedulerService.class);
schedulerService.myMethod();
}
This works just fine - but just once.
I think I understand why - It's because the main thread ends - and so is the spring context so even though myMethod is annotated with #Scheduled it wont work.
I thought of a way to pass this - meaning don't let the main thread die, perhaps like this:
while (true){
Thread.currentThread().sleep(500);
}
That's how, I think, the application context will remain and so is my bean.
Am I right?
Is there a better way to solve this?
I'm using spring 3.1.2.
Thanks.
The main thread should stay active until any non-daemon threads are alive. If you have a <task:annotation-driven/> tag in your application then Spring should start up a executor with a small pool of non-daemon threads for you and the main application should not terminate.
The only thing that you will need to do is to register a shutdown hook also to ensure a cleanup when the VM ends.
context.registerShutdownHook()
The join method is ideal for this:
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
logger.warn("Interrupted", e);
}
Alternatively, here's the old school wait method:
final Object sync = new Object();
synchronized (sync) {
try {
sync.wait();
} catch (InterruptedException e) {
logger.warn("Interrupted", e);
}
}

Categories

Resources