manipule jBPM 5.4 time to simulate timer events - java

I have some processes in jBPM which I test with unit tests (sending events, checking if nodes are triggered, etc).
KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
knowledgeBuilder.add(ResourceFactory.newClassPathResource("process.bpmn"), ResourceType.BPMN2);
knowledgeBase = knowledgeBuilder.newKnowledgeBase();
session = knowledgeBase.newStatefulKnowledgeSession();
....
In some of the processes there are fixed timers (for example 3 weeks). Is there a possibility to manipulate the time jbpm is using so that I can simulate that this period of time is already over?
Btw. I don't want to trigger these notes manually or modify the times in it.
I'm using jbpm 5.4.

One possibility is to use the clock of the session and iterate over all actual running timers.
This will not actually shift time, but can be used to cancel timers, which should be fired in a time span.
Example:
public void shiftTime(long timeToShiftInMs) {
long targetTime = System.currentTimeMillis() + timeToShiftInMs + 10; // 10ms ahead ...
JDKTimerService clock = getSession().getSessionClock();
List<TimerJobInstance> jobs = new ArrayList<>();
for (TimerJobInstance job : clock.getTimerJobInstances()) { // go through all jobs
// He keeps already executed timer without nextFirTime
Date nextFireTime = job.getTrigger().hasNextFireTime();
if (nextFireTime != null) {
long jobTime = nextFireTime.getTime();
if (targetTime > jobTime) { // look if it should be fired after this time
jobs.add(job);
}
}
}
for (TimerJobInstance job : jobs) {
job.getJob().execute(job.getJobContext());
clock.removeJob(job.getJobHandle());
}
}

Related

Spring boot scheduler to stop running if condition is satisfied and run next day again

I have a scheduler(using #Scheduler) running between 7 to 9 PM for every 15 mins. It looks for a file every 15 mins. If the file is found then the scheduler should stop for today and run next day again. How to achieve this in spring boot?
Probably the easiest way is to implement it at the level of business logic.
Spring provides a way to run a periodic task, that's true, but it can't stop the job for some time if a business case is met (the file is found).
Having said that, you could implement the scheduled job as follows:
#Component
public class MyScheduledJob {
private LocalDateTime runNextTime = null;
private boolean isFileFound = false;
#Scheduled(/**here comes your original cron expression: 7 am to 9 pm with an interval of 15 minutes as you say **/)
public void runMe() {
if(isFileFound && LocalDateTime.now().isBefore(runNextTime)) {
// do not run a real job processing
return;
}
isFileFound = checkWhetherFileExists();
if(isFileFound) {
runNextTime = calculateWhenDoYouWantToStartRunningTheActualJobProcessingNextTime();
}
... do actual job processing... Its not clear from the question whether it should do something if the file is not found as well, but I'm sure you've got the point ...
}
}
Since the bean is a singleton you can safely create a state for it, no-one won't change that state anyway.
You can do something like this. You can write your logic for checking files inside this method.
#Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void scheduleFixedRateWithInitialDelayTask() {
long now = System.currentTimeMillis() / 1000;
System.out.println(
"Fixed-rate task with one-second initial delay - " + now);
}
See this for more details.

How to detect if a Scheduled SpringBoot task has been deadlocked?

I have a scheduled task using SpringBoot Scheduled to run Monday through Friday at 10 AM.
I'm running my application in a docker container and my machine is suspended from 6pm to 9am overnight.
When I start my machine, my tasks that were scheduled for 10 hours do not run unless I restart the container before the scheduled time.
I have application logs, no log record occurs that is inside the method with the #Scheduled annotation when this occurs.
With that I believe it's a deadlock.
I wonder if there is any way to detect a deadlock in the Springboot Scheduled programmatically.
My Cron expression: "0 0 10 * * MON-FRI"
Note: I'm testing on my machine to later host on an appropriate server.
AFAIK there is no standard way in Java to detect if the system went in standby/hibernate. Scheduling in Spring is based on the timing facilites in Java, facilites which are not intended to work across OS sleep or hibernate conditions. In short, if the JVM cannot detect when system goes in standby neither can Spring.
As I see it you have the following options:
notify the application when the system is resumed then re-schedule the tasks. This is a possible solution built around pm utils on Ubuntu. This one is for Windows.
add an additional task that runs, say every 10 seconds and reads the system time. If there is an appreciable difference between two time readings it means your system went to sleep and then resumed.
The following for example restarts the context if a time gap (delta) greater than 1s is detected:
#SpringBootApplication
#EnableScheduling
public class Application {
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(Application.class, args);
}
static LocalTime lastDetectedTime;
static long delta = 1000;
static final long CHECK_INTERVAL = 5000;
#Scheduled(fixedDelay = CHECK_INTERVAL, initialDelay = CHECK_INTERVAL)
public static void restartIfTimeMismatch() {
if(lastDetectedTime == null) {
lastDetectedTime = LocalTime.now();
}
LocalTime currentTime = LocalTime.now();
long diff = Duration.between(lastDetectedTime, currentTime).toMillis();
lastDetectedTime = currentTime;
if(diff > CHECK_INTERVAL + delta) {
Thread thread = new Thread(() -> {
context.close();
context = SpringApplication.run(Application.class);
});
lastDetectedTime = null;
thread.setDaemon(false);
thread.start();
}
}
}
Hope it helps.

Java stop scheduled task if it takes more than a specific time

I have a scheduled job which runs every 100 seconds. Sometimes the execution of this method takes a lot of time (which is ok and there is no problem with that). In this situation, the result of the running method is not important to me and I want to re-schedule the job for next 100 second.
What is the best way to force the running job to terminate (return) after a specific time?
My scheduled code is like below:
#Scheduled(fixedDelay = 100*1000)
fun calculateLastDaysStatistics() {
logger.info("affiliate statistics thread Started Successfully")
val processStartDate = Date()
for (i in 1..prevDaysToConsider) {
logger.info("AdZone-Stats prev days $i")
val yesterday = DateUtility.addDay(Date(), -i)
val startDate = DateUtility.getZeroDayTime(yesterday.time)
val endDate = DateUtility.addDay(startDate, 1)
/* This method is probable to take a lot of time */
calculateStatistics(startDate, endDate)
}
val processLength = (Date().time - processStartDate.time) / 1000
logger.info("affiliate statistics thread finished in " + processLength + "s")
}
Thanks.
Try using Fixed Rate instead of Fixed Delay
Here is the article from
Paraschiv.E. The #Scheduled Annotation in Spring. Referred from https://www.baeldung.com/spring-scheduled-tasks
Schedule a Task at a Fixed Rate
#Scheduled(fixedRate = 1000)
public void scheduleFixedRateTask() {
System.out.println(
"Fixed rate task - " + System.currentTimeMillis() / 1000);
}
Note that the beginning of the task execution doesn’t wait for the completion of the previous execution.
This option should be used when each execution of the task is independent.
You can implement a custom Task scheduler using, org.springframework.scheduling.TaskScheduler instead of Annotation based method.
private final TaskScheduler scheduler;
#Autowired
public SchedulingManager(TaskScheduler scheduler) {
this.scheduler = scheduler;
}
In this case,
ScheduledFuture scheduledeFuture = scheduler.schedule(()->{
....You job goes here..
}, new CronTrigger("*/100 * * * * *"));
You can keep track of the scheduled future to make sure it runs max time intended.
scheduledeFuture.get(100,TimeUnit.SECONDS)

How to test task performance, using multitheading?

I have some exercises, and one of them refers to concurrency. This theme is new for me, however I spent 6 hours and finally solve my problem. But my knowledge of corresponding API is poor, so I need advice: is my solution correct or may be there is more appropriate way.
So, I have to implement next interface:
public interface PerformanceTester {
/**
* Runs a performance test of the given task.
* #param task which task to do performance tests on
* #param executionCount how many times the task should be executed in total
* #param threadPoolSize how many threads to use
*/
public PerformanceTestResult runPerformanceTest(
Runnable task,
int executionCount,
int threadPoolSize) throws InterruptedException;
}
where PerformanceTestResult contains total time (how long the whole performance test took in total), minimum time (how long the shortest single execution took) and maximum time (how long the longest single execution took).
So, I learned many new things today - about thread pools, types Executors, ExecutorService, Future, CompletionService etc.
If I had Callable task, I could make next:
Return current time in the end of call() procedure.
Create some data structure (some Map may be) to store start time and Future object, that retuned by fixedThreadPool.submit(task) (do this executionCount times, in loop);
After execution I could just subtract start time from end time for every Future.
(Is this right way in case of Callable task?)
But! I have only Runnable task, so I continued looking. I even create FutureListener implements Callable<Long>, that have to return time, when Future.isDone(), but is seams little crazy for my (I have to double threads count).
So, eventually I noticed CompletionService type with interesting method take(), that Retrieves and removes the Future representing the next completed task, waiting if none are yet present., and very nice example of using ExecutorCompletionService. And there is my solution.
public class PerformanceTesterImpl implements PerformanceTester {
#Override
public PerformanceTestResult runPerformanceTest(Runnable task,
int executionCount, int threadPoolSize) throws InterruptedException {
long totalTime = 0;
long[] times = new long[executionCount];
ExecutorService pool = Executors.newFixedThreadPool(threadPoolSize);
//create list of executionCount tasks
ArrayList<Runnable> solvers = new ArrayList<Runnable>();
for (int i = 0; i < executionCount; i++) {
solvers.add(task);
}
CompletionService<Long> ecs = new ExecutorCompletionService<Long>(pool);
//submit tasks and save time of execution start
for (Runnable s : solvers)
ecs.submit(s, System.currentTimeMillis());
//take Futures one by one in order of completing
for (int i = 0; i < executionCount; ++i) {
long r = 0;
try {
//this is saved time of execution start
r = ecs.take().get();
} catch (ExecutionException e) {
e.printStackTrace();
return null;
}
//put into array difference between current time and start time
times[i] = System.currentTimeMillis() - r;
//calculate sum in array
totalTime += times[i];
}
pool.shutdown();
//sort array to define min and max
Arrays.sort(times);
PerformanceTestResult performanceTestResult = new PerformanceTestResult(
totalTime, times[0], times[executionCount - 1]);
return performanceTestResult;
}
}
So, what can you say? Thanks for replies.
I would use System.nanoTime() for higher resolution timings. You might want to ignroe the first 10,000 tests to ensure the JVM has warmed up.
I wouldn't bother creating a List of Runnable and add this to the Executor. I would instead just add them to the executor.
Using Runnable is not a problem as you get a Future<?> back.
Note: Timing how long the task spends in the queue can make a big difference to the timing. Instead of taking the time from when the task was created you can have the task time itself and return a Long for the time in nano-seconds. How the timing is done should reflect the use case you have in mind.
A simple way to convert a Runnable task into one which times itself.
finla Runnable run = ...
ecs.submit(new Callable<Long>() {
public Long call() {
long start = System.nanoTime();
run.run();
return System.nanoTime() - start;
}
});
There are many intricacies when writing performance tests in the JVM. You probably aren't worried about them as this is an exercise, but if you are this question might have more information:
How do I write a correct micro-benchmark in Java?
That said, there don't seem to be any glaring bugs in your code. You might want to ask this on the lower traffic code-review site if you want a full review of your code:
http://codereview.stackexchange.com

Two Quartz-Worker executing same job twice

We have implemented quartz for scheduling.Every job produced have different key.It was working fine till now. Yesterday we come through a problem as same job is being executed twice or thrice(no particular behaviour) by two different Quartz-Worker threads.
We cant make thread pool size one as we need concurrent jobs.
One noticeable thing about our scheduled job is that it reschedules(daily, weekly or monthly) itself at every run i.e. if a job is scheduled to run daily then it would reschedule itself in next 24 hours but with a random predefined(say 3 hours) time window. For example if a job ran today at 4:10 (i.e between 4:00 and 7:00) then our job will reschedule it self to tomorrow at some random time between 4:00 and 7:00. It may be 4:01 or 6:59 or 5:23 or any other value in the given time window. This process was also working fine and it is still working fine for most of the cases except in some cases where our rescheduling algo is failing to schedule itself in next 24 hours. Instead it is scheduling itself in next 10 sec, 1 hr or any other random value. But it finally stabilizes itself after 2-3 such wrong rescheduling i.e. it finally schedule itself in next 24 hrs. We are suspecting that this may be happening due to the multiple threads accessing the Calendar object (we are using Calendar.getInstance() and cal.add(Calendar.DAY_OF_YEAR, 1) to reschedule the job in next 24 hours). Somehow calendar instance is picking wrong time or is not able to add one day in current time.
So, there are two issues:
1. Multiple Quartz threads acquiring the same job
2. Calendar is not able to add given interval or is picking wrong current time in some particular cases(multiple thread access)
Any help will be appreciated.Reply asap.
Thanks.
Thanks for reply.
I would like to know what is the difference between Statefuljob and #DisallowConcurrentExecution annotation and setting threadPool.threadCount to 1.
Code for rescheduling is as...
Calendar cal = Calendar.getInstance();
Calendar nextCal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone(obj.getTimeZone()));
nextCal.setTimeZone(TimeZone.getTimeZone(obj.getTimeZone()));
Date startTime = null;
SimpleTrigger trigger = null;
JobDataMap dataMap = new JobDataMap();
if (repeatTimeInMillis == null) {
cal.set(Calendar.HOUR_OF_DAY, obj.getStartTime());
nextCal.set(Calendar.HOUR_OF_DAY, obj.getStartTime());
cal.set(Calendar.MINUTE, 0);
nextCal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
nextCal.set(Calendar.SECOND, 0);
if (obj.getScheduleType() == ScheduleType.MONTHLY) { // Monthly
log.info("in monthly schedule");
nextCal.add(Calendar.MONTH, 2);
nextCal.set(Calendar.DAY_OF_MONTH, obj.getDate());
cal.add(Calendar.MONTH, 1);
cal.set(Calendar.DAY_OF_MONTH, obj.getDate());
} else if (obj.getScheduleType() == ScheduleType.WEEKLY) { // Weekly
log.info("in weekly schedule");
nextCal.add(Calendar.WEEK_OF_YEAR, 2);
nextCal.set(Calendar.DAY_OF_WEEK, obj.getDay());
cal.add(Calendar.WEEK_OF_YEAR, 1);
cal.set(Calendar.DAY_OF_WEEK, obj.getDay());
} else if (obj.getScheduleType() == ScheduleType.DAILY) { // Daily
log.info("in daily schedule");
nextCal.add(Calendar.DAY_OF_YEAR, 2);
cal.add(Calendar.DAY_OF_YEAR, 1);
}
long time = obj.getTimeWindow() * 60 * 60 * 1000;
time = Math.round(time * Math.random());
cal.setTimeInMillis(cal.getTimeInMillis() + time);
startTime = cal.getTime();
nextCal.setTimeInMillis(nextCal.getTimeInMillis() + time);
repeatTimeInMillis = nextCal.getTimeInMillis() - cal.getTimeInMillis();
log.info("Rescheduling job at " + startTime);
trigger = newTrigger().usingJobData(dataMap)
.withIdentity(obj.getScheduleJobName(), obj.getScheduleJobGroup()).startAt(startTime)
.withSchedule(simpleSchedule().withIntervalInMilliseconds(repeatTimeInMillis).repeatForever())
.build();
} else {
log.info("Rescheduling job next " + repeatTimeInMillis + " milliseconds.");
cal.setTimeInMillis(cal.getTimeInMillis() + repeatTimeInMillis);
startTime = cal.getTime();
trigger = newTrigger().usingJobData(dataMap)
.withIdentity(obj.getScheduleJobName(), obj.getScheduleJobGroup()).startAt(startTime)
.withSchedule(simpleSchedule().withIntervalInMilliseconds(repeatTimeInMillis).withRepeatCount(1)).build();
}
The StatefulJob interface and #DisallowConcurrentExecution annotation do the same thing.
From the DisallowConcurrentExecution javadoc:
marks a Job class as one that must not have multiple instances
executed concurrently....
This can be used in lieu of implementing the StatefulJob marker
interface that was used prior to Quartz 2.0
Setting the threadPool.threadCount property to 1 would mean at most 1 job of any type can be executing
Using any of these solutions will stop a job executing concurrently and cause any trigger to be placed into a queue to be executed when the previous trigger instance has completed

Categories

Resources