Quartz Scheduler: How to Group Jobs together? - java

I wanted to ask if anybody had the same problem with the Quartz scheduler. I created Jobs with Trigger and JobKeys where i set the Groupnames. But when i print out the group that has been set it is always DEFAULT.
How can i Set this groupname to finally be able to group Jobs together and most importantly cancel only specified groups? With a Code similar like this:
public void unscheduleByGroupname(String groupName) throws SchedulerException {
for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
scheduler.unscheduleJob(new TriggerKey(jobKey.getName(), jobKey.getGroup()));
}
}
Input:
TriggerKey tKey = new TriggerKey("Trigger:" + jobName + "-Somename:" + object.toString(),
"Group:" + jobName + "-Somename:" + object.toString());
JobKey jKey = new JobKey("Job:" + jobName + "-Somename:" + object.toString(),
"Group:" + jobName + "-Somename:" + object.toString());
JobDetail job = JobBuilder.newJob(Somename.class).withDescription("Somename")
.withIdentity(jKey).build();
Trigger trigger = TriggerBuilder.newTrigger().forJob(jKey).startAt(new Date()).withIdentity(tKey).build();
Output Function:
for (String groupName : scheduler.getJobGroupNames()) {
for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
String jobName = jobKey.getName();
String jobGroup = jobKey.getGroup();
// get job's trigger
List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
Date nextFireTime = triggers.get(0).getNextFireTime();
System.out.println("[jobName] : " + jobName + " [groupName] : " + jobGroup + " - " + nextFireTime);}
Output:
[jobName] : Job:-Somename:13 [groupName] : DEFAULT - Tue Jul 19 13:48:40 CEST 2016
[jobName] : Job:-Somename:14 [groupName] : DEFAULT - Tue Jul 19 13:49:11 CEST 2016
[jobName] : Job:-Somename:15 [groupName] : DEFAULT - Tue Jul 19 13:49:41 CEST 2016
[jobName] : Job:-Somename:16 [groupName] : DEFAULT - Tue Jul 19 13:50:11 CEST 2016

When you are seeing up the job identity, you can add the group info. I chain the methods like below, and it works for me (I can see that the group is the desired name that I set):
JobDetail job = JobBuilder.newJob(ScheduledJob.class)
.withIdentity("JOB KEY", "GROUP NAME")
.withDescription("Job description")
.usingJobData(dataMap)
.build();

Related

Execute two schedulers simultaneously with spring-boot #scheduled annotation

I have 2 schedulers, which executes at a fixedDelay of 5s.
I have 2 use-cases:
If If - condition BusinessLogic class is true, then I want to sleep both the schedulers for a time of 3 secs, which means both the schedulers should execute now after 8 secs [5 secs + 3 secs].
If code qualifies the else condition, then both the schedulers should continue to execute at fixed delay of 5 secs.
Code:
Scheduler class:
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
#Component
public class TestSchedulers {
#Autowired
private BusinessLogic businessLogic;
#Scheduled(fixedDelay = 5000)
public void scheduler1(){
Date currentDate = new Date();
System.out.println("Started Sceduler 1 at " + currentDate);
String schedulerName = "Scheduler one";
businessLogic.logic(schedulerName);
}
#Scheduled(fixedDelay = 5000)
public void scheduler2(){
Date currentDate= new Date();
System.out.println("Started Sceduler 2 at " + currentDate);
String schedulerName = "Scheduler two";
businessLogic.logic(schedulerName);
}
}
Business logic class:
import java.util.Random;
import org.springframework.stereotype.Service;
#Service
public class BusinessLogic {
public void logic(String schedulerName) {
if(randomGen() < 100){
System.out.println("\nExecuting If condition for [" + schedulerName + "]");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(randomGen() > 100){
System.out.println("\nExecuting Else condition for [" + schedulerName + "]");
}
}
//Generate random numbers
public int randomGen(){
Random rand = new Random();
int randomNum = rand.nextInt((120 - 90) + 1) + 90;
return randomNum;
}
}
The problem
Both the schedulers are not starting at the same time.
When the if part is executing, then only one schedulers sleep for extra 3 secs, but I want both theschedulers to do so.
Log for reference:
Started Sceduler 1 at Sun May 26 12:34:53 IST 2019
Executing If condition for [Scheduler one]
2019-05-26 12:34:53.266 INFO 9028 --- [ main] project.project.App : Started App in 1.605 seconds (JVM running for 2.356)
Started Sceduler 2 at Sun May 26 12:34:56 IST 2019
Executing If condition for [Scheduler two]
Started Sceduler 1 at Sun May 26 12:35:01 IST 2019
Executing Else condition for [Scheduler one]
Started Sceduler 2 at Sun May 26 12:35:04 IST 2019
Executing Else condition for [Scheduler two]
Started Sceduler 1 at Sun May 26 12:35:06 IST 2019
Executing If condition for [Scheduler one]
Started Sceduler 2 at Sun May 26 12:35:09 IST 2019
Executing Else condition for [Scheduler two]
Started Sceduler 1 at Sun May 26 12:35:14 IST 2019
Executing If condition for [Scheduler one]
Started Sceduler 2 at Sun May 26 12:35:17 IST 2019
Executing If condition for [Scheduler two]
Started Sceduler 1 at Sun May 26 12:35:22 IST 2019
Executing Else condition for [Scheduler one]
Started Sceduler 2 at Sun May 26 12:35:25 IST 2019
Executing Else condition for [Scheduler two]
Started Sceduler 1 at Sun May 26 12:35:27 IST 2019
please help..
In each scheduler you invoke if(randomGen() < 100) independently of each other. So for one scheduler it could give result > 100 and for other < 100 or for both it could be the same. What you will need to do is to run randomGen() outside of the schedulers and store the single result in a way that both schedulers can access it and then they will rely on the same value in their if(randomGenValue < 100) statement and will behave the same way

Java Spring - manage threads for sync requests

I have Java web application with REST calls using SPRING.
I want to control the number of threads the application is opening for the requests.
So I added Thread config:
package myPackage;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
#Configuration
public class ThreadConfig {
#Bean
public TaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(1);
executor.initialize();
return executor;
}
}
I'm using Sync service not Async, I tested it and it doesn't limit the threads handling the requests, it handles them all at the same time.
What I was expecting is when I send 2 requests at a time - either the 2nd request will be thrown or it will wait until the 1st request will finish.
I'm not implementing Thread in my application at all.
This is the relevant code from my controller:
#RestController
public class Module1Controller {
#RequestMapping(method = RequestMethod.GET, path = "/module1")
InterruptedException {
public Module1 Module1() throws InterruptedException {
Date startDate = new Date();
System.out.println("Thread #: " + Thread.currentThread().getId() + " Request received at: " + startDate);
Thread.sleep(10000);
Date endDate = new Date();
long diff = endDate.getTime() - startDate.getTime();
long seconds = TimeUnit.MILLISECONDS.toSeconds(diff);
System.out.println("Thread #: " + Thread.currentThread().getId() + " thread released at: " + endDate + ", total seconds: " + seconds);
return new Module1(new Clock());
}
This is the console result:
Thread #: 34 Request received at: Sun Dec 17 10:16:20 IST 2017
Thread #: 35 Request received at: Sun Dec 17 10:16:21 IST 2017
Thread #: 34 thread released at: Sun Dec 17 10:16:30 IST 2017, total seconds: 10
Thread #: 35 thread released at: Sun Dec 17 10:16:31 IST 2017, total seconds: 10
What am I missing here?
The problem is that the creation of a TaskExecutor in a configuration bean has no effect on your RestController.
The easiest way to make your RestController process only 1 request at a time is to make the handling method synchronized, e.g. like this:
#RequestMapping(method = RequestMethod.GET, path = "/module1")
public synchronized Module1 getModule1() throws InterruptedException {
If you want a certain maximum number of requests to be processed simultaneously you can use a FixedThreadPool, e.g. like this:
// allow only 2 requests at a time, more requests are automatically placed in a queue
private final ExecutorService es = Executors.newFixedThreadPool(2);
#RequestMapping(method = RequestMethod.GET, path = "/module1")
public Module1 getModule1() throws ExecutionException, InterruptedException {
Future<Module1> result = es.submit(new Callable<Module1>() {
#Override
public String call() throws Exception {
try {
//.... do your work here....
return Module1()
} catch (InterruptedException e) {
return null;
}
}
});
return result.get();
}
I'm not sure why you would want to do this. Limiting the number of requests will result in bad performance and users are not going to like this.
You can not control the threads of request in application instead in container. Maybe you want to run some tasks in limited threads in application. You can do like this:
#RestController
public class ThreadController {
#Autowired
private TaskExecutor taskExecutor;
#RequestMapping(method = RequestMethod.GET, path = "/thread")
public void Module1() {
taskExecutor.execute(new Runnable() {
#Override
public void run() {
Date startDate = new Date();
System.out.println("Thread #: " + Thread.currentThread().getId() +
" Request received at: " + startDate);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Date endDate = new Date();
long diff = endDate.getTime() - startDate.getTime();
long seconds = TimeUnit.MILLISECONDS.toSeconds(diff);
System.out.println("Thread #: " + Thread.currentThread().getId() +
" thread released at: " + endDate + ", total seconds: " + seconds);
}
});
}
}
The result:
Thread #: 55 Request received at: Sun Dec 17 22:40:57 CST 2017
Thread #: 55 thread released at: Sun Dec 17 22:41:07 CST 2017, total seconds: 10
Thread #: 55 Request received at: Sun Dec 17 22:41:16 CST 2017
Thread #: 55 thread released at: Sun Dec 17 22:41:26 CST 2017, total seconds: 10
Thread #: 55 Request received at: Sun Dec 17 22:41:32 CST 2017
Thread #: 55 thread released at: Sun Dec 17 22:41:42 CST 2017, total seconds: 10

Esper rules for different users

I recently started programming with Esper and I have a smart wearable that sends pedometer data to my laptop. I then process this data using esper. But suppose I have multiple smart wearables with each an unique MAC address. I use time windows and my question is how can I change my rule file so that the rules only fire for events with the same macaddress and take appropiate action based on this MAC address. My initialization and rule are:
Configuration cepConfig = new Configuration();
cepConfig.addEventType("Steps", Steps.class.getName());
// We setup the engine
EPServiceProvider cep = EPServiceProviderManager.getProvider("myCEPEngine", cepConfig);
EPRuntime cepRT = cep.getEPRuntime();
// We register an EPL statement
EPAdministrator cepSteps1 = cep.getEPAdministrator();
EPStatement cepStatementSteps1 = cepSteps1.createEPL("select * from "
+ "Steps().win:time(1 hour) "
+ "group by macAddress "
+ "having sum(max(steps)-min(steps)) < 100");
cepStatementSteps1.addListener(new rule1Listener());
My Steps class has the following fields:
double steps;
String stepsTimestamp;
String macAddress;
And this is how I insert the events:
Steps steps0 = new Steps(0, new Date(timeStamp).toString(), "K5E45H778");
cepRT.sendEvent(steps0);
Steps steps00 = new Steps(0, new Date(timeStamp).toString(), "LD24ESF74");
cepRT.sendEvent(steps00);
Steps steps1 = new Steps(25, new Date(timeStamp).toString(), "K5E45H778");
cepRT.sendEvent(steps1);
Steps steps2 = new Steps(50, new Date(timeStamp).toString(), "LD24ESF74");
cepRT.sendEvent(steps2);
Steps steps3 = new Steps(55, new Date(timeStamp).toString(), "K5E45H778");
cepRT.sendEvent(steps3);
Steps steps4 = new Steps(105, new Date(timeStamp).toString(), "LD24ESF74");
cepRT.sendEvent(steps4);
Steps steps5 = new Steps(75, new Date(timeStamp).toString(), "K5E45H778");
cepRT.sendEvent(steps5);
Steps steps6 = new Steps(110, new Date(timeStamp).toString(), "K5E45H778");
cepRT.sendEvent(steps6);
This is my output:
Sending tick: Steps: 0.0 Timestamp: Mon Mar 14 18:13:23 CET 2016 Mac Address: K5E45H778
->Rule 1 fired: K5E45H778
Sending tick: Steps: 0.0 Timestamp: Mon Mar 14 18:18:23 CET 2016 Mac Address: LD24ESF7474
->Rule 1 fired: LD24ESF7474
Sending tick: Steps: 25.0 Timestamp: Mon Mar 14 18:23:23 CET 2016 Mac Address: K5E45H778
->Rule 1 fired: K5E45H778
Sending tick: Steps: 105.0 Timestamp: Mon Mar 14 18:28:23 CET 2016 Mac Address: LD24ESF7474
Sending tick: Steps: 55.0 Timestamp: Mon Mar 14 18:33:23 CET 2016 Mac Address: K5E45H778
->Rule 1 fired: K5E45H778
Sending tick: Steps: 75.0 Timestamp: Mon Mar 14 18:38:23 CET 2016 Mac Address: K5E45H778
Sending tick: Steps: 110.0 Timestamp: Mon Mar 14 18:43:23 CET 2016 Mac Address: K5E45H778
Why doesn't the rule fire for the one but last event of 75 steps?
The SQL-standard "group by" clause is for aggregation per group. Thus just adding "group by macAddress" should get it done.

Not able to change quantity of a commerceItem using handleSetOrderByCommerceId

I am not able to change the quantity of commerceItem using handleSetOrderByCommerceId.PFB.
I am using Art Technology Group web commerce platform.
Here is my code snippet:
for (CommerceItem cI : commerceItems) {
if (isLoggingDebug()) {
logDebug("inside handleRemoveItemFromOrder : commerceItems iteration : "+cI.getId() +" : "+ cI.getCatalogRefId());
}
request.setParameter(cI.getId(), cI.getQuantity());
if(cI.getCatalogRefId().equals(dealTobeDeleted)){
long quantity = cI.getQuantity();
//String currentSku = cI.getCatalogRefId();
if(quantity > 1){
// Set the new quantity for the commerce item being updated.
request.setParameter(cI.getCatalogRefId(), quantity-1);
setCheckForChangedQuantity(true);
result = super.handleSetOrderByCommerceId(request, response);
if (isLoggingDebug()) {
logDebug("inside handleRemoveItemFromOrder : after super call handleSetOrderByCommerceId : "+result);
}
}else{
String[] dealArray = new String[]{cI.getId()};
repoItemIdOfCommerceItemGettingRemoved = cI.getCatalogRefId();
setRemovalCommerceIds(dealArray);
if (isLoggingDebug()) {
logDebug("inside handleRemoveItemFromOrder : before super call handleRemoveItemFromOrder : "+repoItemIdOfCommerceItemGettingRemoved +" : "+getRemovalCommerceIds().length);
}
break;
}
}
}
The logs says :
**** debug Fri Sep 18 15:49:55 CAT 2015 1442584195886 /atg/dynamo/servlet/pipeline/RequestScopeManager/RequestScope-37/atg/commerce/order/purchase/CartModifierFormHandler no form errors - staying on same page.
**** debug Fri Sep 18 15:49:55 CAT 2015 1442584195886 /atg/dynamo/servlet/pipeline/RequestScopeManager/RequestScope-37/atg/commerce/order/purchase/CartModifierFormHandler no form errors - staying on same page.
**** info Fri Sep 18 15:49:55 CAT 2015 1442584195889 /com/cellc/online/commerce/pricing/calculators/OrderMonthlyCostCalculator monthlyPrice::::::::::::::509.0
**** debug Fri Sep 18 15:49:55 CAT 2015 1442584195889 /atg/dynamo/servlet/pipeline/RequestScopeManager/RequestScope-37/atg/commerce/order/purchase/CartModifierFormHandler runProcess skipped because chain ID is null
**** debug Fri Sep 18 15:49:55 CAT 2015 1442584195889 /atg/dynamo/servlet/pipeline/RequestScopeManager/RequestScope-37/atg/commerce/order/purchase/CartModifierFormHandler no form errors - staying on same page.
**** debug Fri Sep 18 15:49:55 CAT 2015 1442584195889 /atg/commerce/order/OrderManager Order: o8950004 Version in object: 183 Version in repItem: 183
**** debug Fri Sep 18 15:49:56 CAT 2015 1442584196206 /atg/dynamo/servlet/pipeline/RequestScopeManager/RequestScope-37/atg/commerce/order/purchase/CartModifierFormHandler no form errors - staying on same page.

Java 8 forEach Stream() vs old forEach Loop

I was trying a example code with spring. And a part of code is like below;
private List<Point> points;
long timeTakeninMilis = System.currentTimeMillis();
public List<Point> getPoints() {
return points;
}
public void setPoints(List<Point> points) {
this.points = points;
}
public void drawJava8() {
points.stream().forEachOrdered(
point -> System.out.println("Point : (" + point.getX() + ", "
+ point.getY() + ")"));
System.out.println("Total Time Taken drawJava8(): "
+ (System.currentTimeMillis() - timeTakeninMilis)
+ " miliseconds");
}
public void draw() {
for (Point point : points) {
System.out.println("Point = (" + point.getX() + ", " + point.getY()
+ " )");
}
System.out.println("Total Time Taken draw(): "
+ (System.currentTimeMillis() - timeTakeninMilis)
+ " miliseconds");
}
The OUTPUT,
Jun 30, 2015 11:30:53 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#7daf6ecc: startup date [Tue Jun 30 11:30:53 IST 2015]; root of context hierarchy
Jun 30, 2015 11:30:53 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
Point = (0, 0 )
Point = (-50, 0 )
Point = (0, 50 )
Total Time Taken draw(): 70 miliseconds
Point : (0, 0)
Point : (-50, 0)
Point : (0, 50)
Total Time Taken drawJava8(): 124 miliseconds
Jun 30, 2015 11:30:54 AM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext#7daf6ecc: startup date [Tue Jun 30 11:30:53 IST 2015]; root of context hierarchy
Why it is taking more time?
Or i am doing something wrong?
I was expecting it to be faster or of similar speed...
Please help me understand what is the benefit of the Lambda Expressions?
INFO: I did it in two different programs. Times are taken from those. I merged them here to make it short.
Adding this as an analysis per original poster's request.
We can not really predict the sophisticated analysis and transformation that the modern JIT compiler performs on running code. Hence while benchmarking items such as these, you should not conclude it just by running two method calls.
Instead, create various sample input sets (boundary cases) and check the perofmance by repeatedly calling your test cases without shutting down JVM. In this case for example :
for (int i=0;i<100;i++){draw(); drawJava8();}
Once you have the results, find out average execution and you can safely ignore first execution result as it might not have had optimizations.
So the conclusion you have drawn from your tests is not completely correct.

Categories

Resources