How to schedule tasks with a delay - java

I need to schedule a task to run after 2 minutes. Then when the time is up I need to check if we are still ONLINE. If we are still online I simple don't do anything. If OFFLINE then I will do some work.
private synchronized void schedule(ConnectionObj connectionObj)
{
if(connectionObj.getState() == ONLINE)
{
// schedule timer
}
else
{
// cancel task.
}
}
This is the code I am considering:
#Async
private synchronized void task(ConnectionObj connectionObj)
{
try
{
Thread.sleep(2000); // short time for test
}
catch (InterruptedException e)
{
e.printStackTrace();
}
if(connectionObj.getState() == ONLINE)
{
// don't do anything
}
else
{
doWork();
}
}
For scheduling this task should I use #Async? I may still get many more calls to schedule while I am waiting inside the task() method.
Does SpringBoot have something like a thread that I create each time schedule() gets called so that this becomes easy?
I am looking for something similar to a postDelay() from Android: how to use postDelayed() correctly in android studio?

I'm not sure about an exclusively spring-boot solution, since it isn't something that I work with.
However, you can use ScheduledExecutorService, which is in the base Java environment. For your usage, it would look something like this:
#Async
private synchronized void task(ConnectionObj connectionObj)
{
Executors.newScheduledThreadPool(1).schedule(() -> {
if(connectionObj.getState() == ONLINE)
{
// don't do anything
}
else
{
doWork();
}
}, 2, TimeUnit.MINUTES);
}
I used lambda expressions, which are explained here.

Update
Seeing as how you need to schedule them "on-demand", #Scheduling won't help as you mentioned. I think the simplest solution is to go for something like #Leftist proposed.
Otherwise, as I mentioned in the comments, you can look at Spring Boot Quartz integration to create a job and schedule it with Quartz. It will then take care of running it after the two minute mark. It's just more code for almost the same result.
Original
For Spring Boot, you can use the built in Scheduling support. It will take care of running your code on time on a separate thread.
As the article states, you must enable scheduling with #EnableScheduling.
Then you annotate your method you want to run with #Scheduled(..) and you can either setup a fixedDelay or cron expression, or any of the other timing options to suit your time execution requirements.

Related

Is my approach using Quartz Scheduler's getDefaultScheduler() safe?

I am writing an API that receives requests on when and where to make GET requests, and will then use Quartz to schedule the appropriate times to make those requests. At the moment, I am calling getDefaultScheduler every time a request is made, in order to schedule the appropriate job and trigger. I'm storing the jobs in memory right now, but plan on storing jobs using JDBC later on.
Is this approach safe? We can assume that there may be many concurrent requests to the application, and that the application will make sure there won't be any trigger and job name conflicts.
Yes they are thread safe. But go ahead and look at the JobStore implementation you are using. Here is the DefaultClusteredJobStore impl for storing jobs..
public void storeJob(JobDetail newJob, boolean replaceExisting) throws ObjectAlreadyExistsException,
JobPersistenceException {
JobDetail clone = (JobDetail) newJob.clone();
lock();
try {
// wrapper construction must be done in lock since serializer is unlocked
JobWrapper jw = wrapperFactory.createJobWrapper(clone);
if (jobFacade.containsKey(jw.getKey())) {
if (!replaceExisting) { throw new ObjectAlreadyExistsException(newJob); }
} else {
// get job group
Set<String> grpSet = toolkitDSHolder.getOrCreateJobsGroupMap(newJob.getKey().getGroup());
// add to jobs by group
grpSet.add(jw.getKey().getName());
if (!jobFacade.hasGroup(jw.getKey().getGroup())) {
jobFacade.addGroup(jw.getKey().getGroup());
}
}
// add/update jobs FQN map
jobFacade.put(jw.getKey(), jw);
} finally {
unlock();
}
}

JavaEE - EJB/CDI Method Duration Mechanism

not sure how to title this issue but lets hope description may give better explaination. I am looking for a way to annotate a ejb method or cdi method with a custom annotation like " #Duration" or someothing aaand so to kill methods execution if takes too long after the given duration period. I guess some pseudo code will make everything clear:
public class myEJBorCdiBean {
#Duration(seconds = 5)
public List<Data> complexTask(..., ...)
{
while(..)
// this takes more time than the given 5 seconds so throw execption
}
To sum up, a method takes extremely long and it shall throw a given time duration expired error or something like that
Kinda a timeout mechanism, I dont know if there is already something like this, I am new to javaEE world.
Thanks in advance guys
You are not supposed to use Threading API inside EJB/CDI container. EJB spec clearly states that:
The enterprise bean must not attempt to manage threads. The enterprise
bean must not attempt to start, stop, suspend, or resume a thread, or
to change a thread’s priority or name. The enterprise bean must not
attempt to manage thread groups.
Managed beans and the invocation of their business methods have to be fully controlled by the container in order to avoid corruption of their state. Depending on your usecase, either offload this operation to a dedicated service(outside javaee), or you could come up with some semi-hacking solution using EJB #Singleton and Schedule - so that you could periodically check for some control flag. If you are running on Wildfly/JBoss, you could misuse the #TransactionTimeout annotation for this- as EJB methods are by default transaction aware, setting the timeout on Transaction will effective control the invocation timeout on the bean method. I am not sure, how it is supported on other applications servers.
If async processing is an option, then EJB #Asynchronous could be of some help: see Asynchronous tutorial - Cancelling and asynchronous operation.
As a general advice: Do not run long running ops in EJB/CDI. Every request will spawn a new thread, threads are limited resource and your app will be much harder to scale and maintain(long running op ~= state), what happens if your server crashes during method invocation, how would the use case work in clustered environment. Again it is hard to say, what is a better approach without understanding of your use case, but investigate java EE batch api, JMS with message driven beans or asynchronous processing with #Asynchronous
It is a very meaningful idea – to limit a complex task to a certain execution time. In practical web-computing, many users will be unwilling to wait for a complex search task to complete when its duration exceeds a maximally acceptable amount of time.
The Enterprise container controls the thread pool, and the allocation of CPU-resources among the active threads. It does so taking into account also retention times during time-consuming I/O-tasks (typically disk access).
Nevertheless, it makes sense to program a start task variable, and so now and then during the complex task verify the duration of that particular task. I advice you to program a local, runnable task, which picks scheduled tasks from a job queue. I have experience with this from a Java Enterprise backend application running under Glassfish.
First the interface definition Duration.java
// Duration.java
#Qualifier
#Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
#Documented
#Retention(RetentionPolicy.RUNTIME)
public #interface Duration {
public int minutes() default 0; // Default, extended from class, within path
}
Now follows the definition of the job TimelyJob.java
// TimelyJob.java
#Duration(minutes = 5)
public class TimelyJob {
private LocalDateTime localDateTime = LocalDateTime.now();
private UUID uniqueTaskIdentifier;
private String uniqueOwnerId;
public TimelyJob(UUID uniqueTaskIdentifier, String uniqueOwnerId) {
this.uniqueTaskIdentifier = uniqueTaskIdentifier;
this.uniqueOwnerId = uniqueOwnerId;
}
public void processUntilMins() {
final int minutes = this.getClass().getAnnotation(Duration.class).minutes();
while (true) {
// do some heavy Java-task for a time unit, then pause, and check total time
// break - when finished
if (minutes > 0 && localDateTime.plusMinutes(minutes).isAfter(LocalDateTime.now())) {
break;
}
try {
Thread.sleep(5);
} catch (InterruptedException e) {
System.err.print(e);
}
}
// store result data in result class, 'synchronized' access
}
public LocalDateTime getLocalDateTime() {
return localDateTime;
}
public UUID getUniqueTaskIdentifier() {
return uniqueTaskIdentifier;
}
public String getUniqueOwnerId() {
return uniqueOwnerId;
}
}
The Runnable task that executes the timed jobs - TimedTask.java - is implemented as follows:
// TimedTask.java
public class TimedTask implements Runnable {
private LinkedBlockingQueue<TimelyJob> jobQueue = new LinkedBlockingQueue<TimelyJob>();
public void setJobQueue(TimelyJob job) {
this.jobQueue.add(job);
}
#Override
public void run() {
while (true) {
try {
TimelyJob nextJob = jobQueue.take();
nextJob.processUntilMins();
Thread.sleep(100);
} catch (InterruptedException e) {
System.err.print(e);
}
}
}
}
and in a seperate code, the staring of the TimedTask
public void initJobQueue() {
new Thread(new TimedTask()).start();
}
This functionality actually implements a batch-job scheduler in Java, using annotations to control the end-task time limit.

how to reduce quartz scheduling latency

Im using Quartz under Spring backed by a jdbc job store, and im trying to make it trigger a job "now":
Trigger adHocTrigger = TriggerBuilder.newTrigger().withIdentity(adHocTriggerKey).forJob(jobKey).startNow().build();
quartzScheduler.scheduleJob(adHocTrigger); //now
the measured latency between this call and the time the job actually starts executing is ~30 seconds by default. here's an example job to measure one-off trigger latency that i used:
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
Trigger trigger = context.getTrigger();
if (!trigger.mayFireAgain()) {
//its a one-off, compute latency
long latency = System.currentTimeMillis() - trigger.getFinalFireTime().getTime();
logger.info("firing latency is {} millis",latency);
}
}
after reading the documentation i found the reason for the latency is the "org.quartz.scheduler.idleWaitTime" configuration parameter (basically the job store polling frequency?), which can be configured as low as 1000 millis (at which point the latency im getting is on the order of 900 millis).
I understand that setting it this low may cause db thrashing (im using a jdbc job store) and is therefore not recommended, but is there any way to achieve low latency without resorting to this?
is there no optional configuration property that will cause "fire now" to actually do?
One way to solve this without lowering idleWaitTime is to modify QuartzScheduler slightly to support transactions. I don't use Spring, so I don't know what that would look like there, but this is the basic idea.
class TransactionAwareScheduler extends QuartzScheduler {
#Override
protected void notifySchedulerThread(long candidateNewNextFireTime) {
if (insideTransaction) {
transaction.addCommitHook(() -> {
super.notifySchedulerThread(candidateNewNextFireTime);
});
}
} else {
super.notifySchedulerThread(candidateNewNextFireTime);
}
}
It resolved the issue completely for us.
The documentation says 'triggerJob' will fire the job immediately. Check whether this satisfies your requirement.
quartzScheduler.triggerJob(jobKey);

How can I make a JUnit test wait?

I have a JUnit test that I want to wait for a period of time synchronously. My JUnit test looks like this:
#Test
public void testExipres(){
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExipration("foo", 1000);
// WAIT FOR 2 SECONDS
assertNull(sco.getIfNotExipred("foo"));
}
I tried Thread.currentThread().wait(), but it throws an IllegalMonitorStateException (as expected).
Is there some trick to it or do I need a different monitor?
How about Thread.sleep(2000); ? :)
Thread.sleep() could work in most cases, but usually if you're waiting, you are actually waiting for a particular condition or state to occur. Thread.sleep() does not guarantee that whatever you're waiting for has actually happened.
If you are waiting on a rest request for example maybe it usually return in 5 seconds, but if you set your sleep for 5 seconds the day your request comes back in 10 seconds your test is going to fail.
To remedy this JayWay has a great utility called Awatility which is perfect for ensuring that a specific condition occurs before you move on.
It has a nice fluent api as well
await().until(() ->
{
return yourConditionIsMet();
});
https://github.com/jayway/awaitility
In case your static code analyzer (like SonarQube) complaints, but you can not think of another way, rather than sleep, you may try with a hack like:
Awaitility.await().pollDelay(Durations.ONE_SECOND).until(() -> true);
It's conceptually incorrect, but it is the same as Thread.sleep(1000).
The best way, of course, is to pass a Callable, with your appropriate condition, rather than true, which I have.
https://github.com/awaitility/awaitility
You can use java.util.concurrent.TimeUnit library which internally uses Thread.sleep. The syntax should look like this :
#Test
public void testExipres(){
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExipration("foo", 1000);
TimeUnit.MINUTES.sleep(2);
assertNull(sco.getIfNotExipred("foo"));
}
This library provides more clear interpretation for time unit. You can use 'HOURS'/'MINUTES'/'SECONDS'.
If it is an absolute must to generate delay in a test CountDownLatch is a simple solution. In your test class declare:
private final CountDownLatch waiter = new CountDownLatch(1);
and in the test where needed:
waiter.await(1000 * 1000, TimeUnit.NANOSECONDS); // 1ms
Maybe unnecessary to say but keeping in mind that you should keep wait times small and not cumulate waits to too many places.
Mockito (which is already provided via transitive dependencies for Spring Boot projects) has a couple of ways to wait for asynchronous events, respectively conditions to happen.
A simple pattern which currently works very well for us is:
// ARRANGE – instantiate Mocks, setup test conditions
// ACT – the action to test, followed by:
Mockito.verify(myMockOrSpy, timeout(5000).atLeastOnce()).delayedStuff();
// further execution paused until `delayedStuff()` is called – or fails after timeout
// ASSERT – assertThat(...)
Two slightly more complex yet more sophisticated are described in this article by #fernando-cejas
My urgent advice regarding the current top answers given here: you want your tests to
finish as fast as possible
have consistent results, independent of the test environment (non-"flaky")
... so just don't be silly by using Thread.sleep() in your test code.
Instead, have your production code use dependency injection (or, a little "dirtier", expose some mockable/spyable methods) then use Mockito, Awaitly, ConcurrentUnit or others to ensure asynchronous preconditions are met before assertions happen.
You could also use the CountDownLatch object like explained here.
There is a general problem: it's hard to mock time. Also, it's really bad practice to place long running/waiting code in a unit test.
So, for making a scheduling API testable, I used an interface with a real and a mock implementation like this:
public interface Clock {
public long getCurrentMillis();
public void sleep(long millis) throws InterruptedException;
}
public static class SystemClock implements Clock {
#Override
public long getCurrentMillis() {
return System.currentTimeMillis();
}
#Override
public void sleep(long millis) throws InterruptedException {
Thread.sleep(millis);
}
}
public static class MockClock implements Clock {
private final AtomicLong currentTime = new AtomicLong(0);
public MockClock() {
this(System.currentTimeMillis());
}
public MockClock(long currentTime) {
this.currentTime.set(currentTime);
}
#Override
public long getCurrentMillis() {
return currentTime.addAndGet(5);
}
#Override
public void sleep(long millis) {
currentTime.addAndGet(millis);
}
}
With this, you could imitate time in your test:
#Test
public void testExpiration() {
MockClock clock = new MockClock();
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExpiration("foo", 1000);
clock.sleep(2000) // wait for 2 seconds
assertNull(sco.getIfNotExpired("foo"));
}
An advanced multi-threading mock for Clock is much more complex, of course, but you can make it with ThreadLocal references and a good time synchronization strategy, for example.
Using Thread.sleep in a test is not a good practice. It creates brittle tests that can fail unpredictably depending on environment ("Passes on my machine!") or load. Don’t rely on timing (use mocks) or use libraries such as Awaitility for asynchroneous testing.
Dependency : testImplementation 'org.awaitility:awaitility:3.0.0'
await().pollInterval(Duration.FIVE_SECONDS).atLeast(Duration.FIVE_SECONDS).atMost(Duration.FIVE_SECONDS).untilAsserted(() -> {
// your assertion
});

Timer Service in ejb 3.1 - schedule calling timeout issue

I have created simple example with #Singleton, #Schedule and #Timeout annotations to try if they would solve my problem.
The scenario is this: EJB calls 'check' function every 5 secconds, and if certain conditions are met it will create single action timer that would invoke some long running process in asynchronous fashion. (it's sort of queue implementation type of thing). It then continues to check, but while the long running process is there it won't start another one.
Below is the code I came up with, but this solution does not work, because it looks like asynchronous call I'm making is in fact blocking my #Schedule method.
#Singleton
#Startup
public class GenerationQueue {
private Logger logger = Logger.getLogger(GenerationQueue.class.getName());
private List<String> queue = new ArrayList<String>();
private boolean available = true;
#Resource
TimerService timerService;
#Schedule(persistent=true, minute="*", second="*/5", hour="*")
public void checkQueueState() {
logger.log(Level.INFO,"Queue state check: "+available+" size: "+queue.size()+", "+new Date());
if (available) {
timerService.createSingleActionTimer(new Date(), new TimerConfig(null, false));
}
}
#Timeout
private void generateReport(Timer timer) {
logger.info("!!--timeout invoked here "+new Date());
available = false;
try {
Thread.sleep(1000*60*2); // something that lasts for a bit
} catch (Exception e) {}
available = true;
logger.info("New report generation complete");
}
What am I missing here or should I try different aproach? Any ideas most welcome :)
Testing with Glassfish 3.0.1 latest build - forgot to mention
The default #ConcurrencyManagement for singletons is ConcurrencyManagementType.CONTAINER with default #Lock of LockType.WRITE. Basically, that means every method (including generateReports) is effectively marked with the synchronized keyword, which means that checkQueueState will block while generateReport is running.
Consider using ConcurrencyManagement(ConcurrencyManagementType.BEAN) or #Lock(LockType.READ). If neither suggestion helps, I suspect you've found a Glassfish bug.
As an aside, you probably want persistent=false since you probably don't need to guarantee that the checkQueueState method fires every 5 seconds even when your server is offline. In other words, you probably don't need the container to fire "catch ups" when you bring your server back online.

Categories

Resources