Execute method in a scheduled manner - java

I want to execute a call to a particular method every minute, and it should get called with the server startup. This should be a single thread.
I tried using the CRON job , but am facing some issues with it.
Is there any way through which I can achieve it

Use ExecutorServices...
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate( new Runnable()
{
#Override
public void run()
{
// call your method here
}
}, 0, 1, TimeUnit.MINUTES );

For a similar task i am using a Quartz scheduler. It is very easy to use. My intervals are larger than a minute though, but this should not matter.
You have the option to specify how many threads your scheduler will be using in a config file.
http://quartz-scheduler.org/
http://quartz-scheduler.org/api/2.0.0/

If you are using JBoss (may also apply to other AS, I have no data on them), you may want to try the bundled quartz scheduler. It offers very finegrained job control. You don't have to use the bundled version though, and are free to use it as dependency on the AS of your choice.

You can use Spring Tasks to achieve this easily using annotations. They are in the context jars so you shouldn't have to add any new jars to achieve this.
In your appContext add (adjust the pool-size accordingly):
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="2"/>
<task:scheduler id="myScheduler" pool-size="2"/>
You'll need to pull in the appropriate namespace too:
xmlns:task="http://www.springframework.org/schema/task"
After you do all of this you should be able to just annotate the method you want to be called. Since you want your method called every minute you should use fixedRate:
#Scheduled(fixedRate=60000)
Doing this should force the call to run on startup and every minute thereafter. The time as you can probably see is set in milliseconds.

Execute a particular method every minute? This sounds like you need a Timer. Have a look at this article for more information. Timer executes the method at a background thread - why is it important to execute the method within your main thread?

class DemoThread extends Thread {
public void run() {
while(true) {
try {
sleep(60000);
}
catch(InterruptedException e) {
}
// call some random method here
}
}
}
Init the Thread and run it.
DemoThread thread = new DemoThread();
thread.start();

Related

How to have an asynchronous and non-concurrent scheduler in Spring?

I have in the main class that starts the app:
#SpringBootApplication
#EnableAsync
public class ExperianRequestBotApplication extends RefApplication {
public ExperianRequestBotApplication() throws RefException {
super();
}
public static void main(String[] args) throws RefException {
try {
new ExperianRequestBotApplication().start(args);
} catch (Exception e) {
System.out.println(" ------- OFFLINE ------- ");
System.out.println("La aplicación no esta disponible por :" + e);
}
}
}
and a scheduler
#Component
public class ScheduledTaskSincronizarContactos {
#Autowired
private ExperianRequestBotService experianRequestBotService;
private final static Logger LOG = LoggerFactory.getLogger(ScheduledTaskSincronizarContactos.class);
// Método Shedule encargado de sincronizar los usuarios modificados con Experian
#Async
#Scheduled(cron = "0 */15 * ? * *")
public void SincronizarContactos() throws Exception {
I want to prevent the scheduler from being launched again if the internal process takes more than 15 minutes to start the task again.
I can't find the way. I have tried implementing #DisallowConcurrentExecution with the quartz library but it is still concurrent.
Any ideas?
I've faced a similar issue with concurrency while using spring scheduling. We had a lot of jobs all running on the same service and interfering with each other. We switched to using Quartz Scheduling - felt simpler than the Spring multithreaded scheduler with a bunch of other features that we wanted. This repo was really helpful.
https://gitlab.com/johnjvester/jpa-spec-with-quartz/-/blob/master/src/main/java/com/gitlab/johnjvester/jpaspec/config/QuartzConfig.java
Quartz scheduling also has the advantage of being persistent - when it starts up, it will trigger all the missed jobs. One can also alter cron statements programmatically. This might be an overkill for your use case but it is worth a look. :) Also, what Wasif said - use delays to define when the job should be run vs a cron expression and you're guaranteed a win even with Spring!
By default, all scheduled tasks run on a single thread in Spring boot unless you define a thread pool implementation yourself.
Here is a link for more reference that came in handy for me once:
https://crmepham.github.io/spring-boot-multi-thread-scheduling/
I'm surprised to see that your having the issue with the tasks running concurrently in the first place.
How i'm currently doing scheduled tasks whenever i need to, i place #EnableScheduling annotation on the main class, and use fixed rate and initial delay.
Maybe you could use fixed rate and initial delay instead of cron to achieve what you are trying to do.
Remove #Async from the method. #Async causes the method to be called on a separate executor.
The problem is that your job might take longer than the time planned for its run and the time in between runs. One idea would be to store somewhere the last start time and the last end time of the cron job. If the last end time is earlier than the last start time, then at the next run, ignore everything. That is, you need something like this:
#SpringBootApplication
#EnableAsync
public class ExperianRequestBotApplication extends RefApplication {
public ExperianRequestBotApplication() throws RefException {
super();
}
public static void main(String[] args) throws RefException {
try {
if (ExperianRequestBotApplication.shouldRun()) {
new ExperianRequestBotApplication().start(args);
}
} catch (Exception e) {
System.out.println(" ------- OFFLINE ------- ");
System.out.println("La aplicación no esta disponible por :" + e);
}
}
}
Note that a conditional with a boolean validator is wrapped around the bulk of your job. That shouldRun should check whether the last start date is smaller than the last end date. You will also need to make sure that your job manages these values. It is true that with this approach your job is still being executed every 15 minutes, but, if the last run has not finished yet, then the current run will be extremely quick, it will just check whether the job is still running and if so, then it will avoid doing anything. Otherwise it will properly execute the job. This is simple to implement, protects you from ending up in running the same long job multiple times simultaneously or in sequence and will provide some breathing space for the system to perform other operations.
Thanks all for your answers, finally we've decide to use quartz library. The easiest way, using #DisallowConcurrentExecution we can have async jobs not executing concurrently.

Liferay 7.1 - Kill a thread execution from scheduler jobs

I have my following job in Liferay 7.1 :
#Component(
immediate = true, property = {"cron.expression=0 5 10 * * ? *"},
service = CustomJob.class
)
public class CustomJob extends BaseMessageListener {
....
#Override
protected void doReceive(Message message) throws Exception {
// HERE I CALL A SERVICE FUNCTION TO INACTIVATE USER, SEND MAILS, READ FILES TO IMPORT DATA
RunnableService rs = new RunnableService();
rs.run();
}
....
}
And my RunnableService :
public class RunnableService implements Runnable {
#Override
public synchronized void run() {
// DO MY STUFF
}
}
The job is working great, but another instance of the job can be started even when the service execution from the first call hasn't finished.
Is there any solutions to kill the first process ?
Thanks,
Sounds like there are several options, depending on what you want to achieve with this:
You shouldn't interrupt threads with technical measures. Rather have your long-running task check frequently if it should still be running, otherwise terminate gracefully - with the potential of cleaning up after itself
You can implement your functionality with Liferay's MessageBus - without the need to start a thread (which isn't good behavior in a webapp anyway). The beauty of this is that even in a cluster you end up with only one concurrent execution.
You can implement your functionality outside of the Liferay process and just interact with Liferay's API in order to do anything that needs to have an impact on Liferay. The beauty of this approach is that both can be separated to different machines - e.g. scale.

Execute a method after the application starts using Spring

I have this structure in my Service component in my Spring:
#Autowired
PointController controller;
#Autowired
ParametroService parametroService;
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
List<IntRaptMec> allPointments = getNotValidated();
for(IntRaptMec pointment : allPointments) {
controller.validate(pointment.getIdTemp());
}
}
};
public void doValidationsTask() {
Parametro parametroTempo = parametroService.getParametro("1", "ATRC_MEC", "TEMPO_VERIFICACAO");
timer.scheduleAtFixedRate(
timerTask,
Integer.parseInt(parametroTempo.getValor()) * oneMinute,
Integer.parseInt(parametroTempo.getValor()) * oneMinute
);
}
All that I want is that after the Spring Application fully initializes it will execute the method run() inside the TimerTask. Then, after a given time in minutes that will be get from the parametroService.getParametro(), execute this task again.
I tried to follow this link from the docs:
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#scheduling-annotation-support
But seems that I can't dinamically sets the Delay time that a specific task will be executed
You can annotate your run() method with #EventListener or create a new such annotated method which will call run():
#EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
run();
}
If you don't use context which supports refresh() operation, you should be fine.
If you use such context (and you don't want run() to execute on context refresh) make sure you store this state within your bean.
More info on standard Spring events.
You are correct that annotation #Scheduled does not allow you to read delay parameter dynamically. For that reason and because this annotation takes delay parameter only in milliseconds or as crone expression which is not user friendly, I wrote my own utility that does it. The Utility is available as part of Open Source MgntUtils library. You will need to write your classes that will extend classes provided in the library and then you will get the desired functionality. But it does require a little bit of work. However the library comes with example package that has source code of working example with detailed explanation in javadoc. If you are interested library is available at Github and at Maven Central. In both places it is available with sources and javadoc. The desired feature is described in detail in javadoc. If you download and unzip javadoc into folder c:\tmp then look at URL file:///C:/tmp/javadoc/com/mgnt/lifecycle/management/backgroundrunner/package-summary.html for detailed description on how to use this feature. For working code example look in the sources at package com.mgnt.lifecycle.management.backgroundrunner.example
Also, there is an article that explains about the features of the library, except that this particular feature is not described in that article yet. Here is the link: Open Source Java library with stack trace filtering, Silent String parsing, Unicode converter and Version comparison
You can implement a spring SmartLifecycle interface. This will get invoked when Spring context is loaded completely. And Then you can start the timertask.
public class TimerTaskInvoker implements SmartLifecycle{
#override
public void start(){
timer.scheduleAtFixedRate(timerTask);
}
}
You can check the reference - https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/SmartLifecycle.html
#PostConstruct may be the annotation you need.
https://www.baeldung.com/running-setup-logic-on-startup-in-spring
You can use spring scheduler and specify the initialDelay and fixedRate using the #Scheduled annotation.
#EnableScheduling
class CustomScheduler{
#Scheduled(fixedRate = 1000, initialDelay = 1000)
public void taskYouWantToPerform() {
List<IntRaptMec> allPointments = getNotValidated();
for(IntRaptMec pointment : allPointments) {
controller.validate(pointment.getIdTemp());
}
}
}
For more details refer this

Trigger #Scheduled method

I use Spring's scheduler (#EnableScheduling) and have the following #Scheduled method, which is called every minute:
#Component
public class ScheduledTask {
#Scheduled(fixedRate = 60*1000)
public void run() {
// ...
Now I would like to be able to trigger a scheduler run, on demand, from another place in the code.
I can inject ScheduledTask and just call the run method. However I want to make sure that there is only one thread running the run method at any given time. In other words, if the scheduler is currently running run I want the call to be ignored.
Also I want to call run asynchronously, but this can be easily addressed by using #EnableAsync and #Async.
Is there any Spring feature that can be used in this scenario?
Edited as of comment:
Just use an AtomicBoolean.
#Component
public class ScheduledTask {
private AtomicBoolean isRunning = new AtomicBoolean(false);
#Scheduled(fixedRate = 60*1000)
public void run() {
if (isRunning.compareAndSet(false, true)) {
// ... do your things
//whenever you are done
isRunning.set(false);
}
I don't think there's something simpler in Spring. It makes no sense as it is really a flag thing.
Edit:
If you want to use it in several places of the application, consider implementing your own annotation with the semaphore or atomic boolean embedded.

Is there a way to pause a unit test without blocking the thread

I'm using play 1.2.4 and I'm trying to set up a unit test to test a job.
My job runs at every 2 second and changes the status of certain objects based on some conditions. This is what I use to do this.
#Every("2s")
public class GameScheduler extends Job {
public void doJob(){
//Fetch of object from db and status change based on conditions happens here
}
}
Now in my unit test, I setup those conditions but I want the test to wait say 3 seconds before fetching one of the setup objects and do an assert Equals on its status to see if the job... well did it's job.
If I use
pause(3000);
or something like
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
The test stops but the job also stops. It seems like the job and the test are on the same thread. Is there a way to pause the test without stopping the job? Something like the await() method in the controller
You don't need to test the scheduler because it is supposed to work (since the framework is handling it). What you need is just test if the doJob method is doing its work. So, just write a test like this:
GameScheduler job = new GameScheduler();
job.doJob();
// assert whatever you want here
Though simply testing the job (without waiting for the scheduler to run it for you) would do the trick in most (read this as: probably all) situations, there are some in which it might be interesting to not have to trigger it manually.
For instance, you have a cluster of play apps that share a common configuration set. Change one config in one slave, all the others take note and do the same. Let's say the configuration is kept in memcached. One useful unit test is to manually change some setting using Cache.set, wait for the amount of time it takes for the configurationObserver job to run, then check that the internal config has been updated. This would be even more helpful if there would be a series of jobs updating the configuration, etc.
To do that, you must remember that play in DEV mode uses one thread (this helps debugging a lot, btw). You can simply add this line to your application.conf: %test.application.mode=prod and you'll have multiple threads.
Later edit: It appears that setting the mode to prod doesn't really help in this case. What does help is this: use some "await" magic.
#Test
public void myTest() {
final Lock lock = new ReentrantLock();
final Condition goAhead = lock.newCondition();
/* Here goes everything you need to do before "pausing" */
lock.lock();
try {
/**
* Set whatever time limit you want/need
* You can also use notifiers like goAhead.signal(), from within another thread
*/
goAhead.await(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
assertTrue(whateverINeedToTest);
} finally {
lock.unlock();
}
}

Categories