I need to cancel Spring timer execution or at least change the execution frequency based on some conditions. Was using both org.springframework.scheduling.quartz.SimpleTriggerBean and org.springframework.scheduling.timer.ScheduledTimerTask. Cannot find the way how to do it.
NOTE: This is for Spring 3.0+
Read Spring documentation on scheduling tasks
Use a TaskScheduler service, such as a TimerManagerTaskScheduler or ThreadPoolTaskScheduler.
Schedule your task by calling some TaskScheduler.schedule*() method and store the returning ScheduledFuture.
When you want to cancel execution, invoke ScheduledFuture.cancel(). That will stop further invocations of your task. At this time, you can reschedule if you want by calling TaskScheduler.schedule*() for your task with different parameters.
This is by far not the best solution but if you can't come up with anything else you could always use a boolean that would be checked each time the event is fired and if the boolean is false the run method of the timertask should immediately terminate.
The solution is to assign an id to the org.springframework.scheduling.timer.TimerFactoryBean and then retrieve this bean from the application, cast it to Timer and call cancel method on that object.
Related
I'm using a ScheduledExecutorService to run a particular job (implemented as an ordinary Runnable) periodically once in a minute (using method scheduleAtFixedDelay()).
Occasionally, however, I would like it to wake up immediately, invoke the Runnable and then return to its ordinary policy (i.e. wait 1 minute again).
Is there a simple way to achieve this?
I've checked the API of the ScheduledExecutorService and its superclasses, but so far didn't find anything suitable.
Of course I could resort to some other method, like pass the same Runnable to a separate Thread created for the exceptional purpose, but using a method of the ScheduledExecutorService would be more elegant.
Just remember the ScheduledFuture from your call to schedule.
If you then want to run it ahead of time, call future.cancel(), submit the Task again for immediate execution and then schedule it again.
I've configured Camunda engine with org.camunda.bpm.engine.test.mock.MockExpressionManager.
At first glance it works as expected: when I do
Mocks.register("myDelegate", myDelegateMock), the bpmn process invokes my mock, but not the real delegate.
But when there is a task, that invoked by some timer boundary event, the mock is ignored and the real delegate becomes invoked.
I've looked at the code, and found that mocks are stored in the ThreadLocal. And if the tasks is invoked by timer, the execution happens in different thread. And that's looks like a root cause of such behavior. Probably mocks also will not work if the task is marked as asynchronous.
I've also tried the extension
https://github.com/camunda/camunda-bpm-mockito
but looks like internally it uses the same Mocks.register, and also doesn't work for me.
May be there are some other possibilities to mock delegate that will work for the case with timer?
Well, the this is already answered in the thread you mentioned:
Mocks.register is meant to be used in a purely single-threaded,
no-job-executor, "unit test" environment. In such an environment,
instead of setting the time and waiting for the job executor to
process the jobs, you need to explicitly trigger the timer job in your
own testing thread:
Job job = processEngineRule.getManagementService().createJobQuery().singleResult();
processEngineRule.getManagementService().executeJob(job.getId());
Then it should happily resolve the name and should work.
So the solution is: let the process run into the timer event, and then manually execute the job() so the process continues as if the timer was reached. This is a good idea even without the single-thread problem: do not simulate timers in camunda tests, just verify that the process is waiting in the correct step and control if the timer condition (due date) is equal to the one you expected.
I want to terminate(or abort) a task immediately when it is running, not to wait its ending. I search in JDK, the Timer class and the TimerTask class not satisfied, their cancel method is not proper for me, for the task will contiue to execute util it finish, but I want to stop it immediately.
What should I do? I serach for Spring and Quartz, but no good idea...
This is not something that is recommended to do in a multi threaded environment as it can break your code in all sorts of ways. For example imagine you are half way through changing something and suddenly your thread gets killed leaving it in a half-modified state. Because it is not recommended no easy way is provided to do it.
The correct way to do this is to use a Thread and interrupt it.
http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html
Inside your Thread code you can check isInterrupted() at times where it would be appropriate to abort and abort, but the abort is controlled by the running thread which is the only thing that knows when it is safe to do so.
The ScheduledExecutorService also allows you to work with a ScheduledFuture and cancel that, which then works in the same way as interrupting the thread does.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#cancel(boolean)
I use the Java's Timer to schedule a task to run after some interval of time.
myTimer.schedule(myTask, delayTime);
At any point in time, is it possible to check if there is any task scheduled to be run (but has not run yet)? If so, how would I do that?
If not, what is the alternative(s) to Timer do I have?
You can (and should) use ScheduledExecutorService instead of Timer.
It handles thread crashes in a robust manner and has more flexible API
You can just add a boolean field to myTask's class, which will be set true at first execute.
Keep it simple.
Do Java/Android have any constructs available for running a method within a class at some time interval?
I am aware of the Scheduler and Timer classes but I need to avoid instantiating another class. The method must not run in another separate thread. Running an AsyncTask or Handler results in a separate thread.
The method must not run in another separate thread
Because of this requirement you only have one reasonable solution, you must wait in your own thread, like this:
for (int i = 0; i < 100; i++) {
long intervalInMs = 1000; // run every second
long nextRun = System.currentTimeMillis() + intervalInMs;
callAMethod();
if (nextRun > System.currentTimeMillis()) {
Thread.sleep(nextRun - System.currentTimeMillis());
}
}
Note, that if the method call takes longer time than you want to wait, it will not call twice (because you only have one Thread) You can detect it by writing an else clause to the if, and make some modifications (e.g. increase the intervalInMs);
You need to use the AlarmManager for this.
Check this SO for a good overview: Android: How to use AlarmManager
I would not try to manage this within your own thread, but let the Android framework handle this for you. Not sure why you need it to run in the same Thread.
Create a custom Timer that receives a Listener, then when your time has elapsed, send the callback to the object that has created the Timer in his thread.
This will create a new Thread for the Timer, but the method you want to execute, will be executed on the original's object thread
If you really must do this in the same thread without blocking, one possible solution is to do some kind of polling. I imagine code which periodically calculates how much time has passed since the last time the method fired. If the configured time period has elapsed, then fire the method again.
This kind of solution seems complex to implement. How often do you execute the polling code? How do you execute the polling code within the logic of the rest of the app that is likely continuing to execute in the mean time? These are only the technical challenges that come immediately to mind. I'm sure there are others. With this in mind, I think the better solution is to rethink your restrictions. Why do you want to do this in the same thread? You should think hard about your reasons and consider using a separate thread (whether you roll it yourself with Timer or you use the Android platform to manage it for you with AlarmManager.