I am Using Quarts Scheduler for job scheduling. I have various jobs which gets medical report of different users daily and send that report to individual user. Each job has a specific user associated with it.
Before each job starts executing its business logic the JobListener implementation class creates an instance of the class UserJobExecution.
public class UserJobExecution
{
static ThreadLocal currentExecution = new ThreadLocal()
User user;
static UserJobExecution getCurrent(){
(UserJobExecution ) currentExecution.get();
}
UserJobExecution(String jobName){
try
{
user = getUserFromDB(jobName);
}
catch(e)
{
e.printStackTrace();
}
}
User getUser(){
return user;
}
//rest of the code
}
class WebServiceUtil{
static HttpClient client = new HttpClient(new MultiThreadedHttpConnectionManager());
User user;
WebServiceUtil(User user){
this.user = user;
}
static WebServiceUtil getDefaultWs(){
UserJobExecution userJobExecution = UserJobExecution.getCurrent();
return (new WebServiceUtil(userJobExecution.getUser()));
}
static execute(String request){
getDefaultWs().executeService(request);
}
}
Both the above classes has a User object that has two fields username and password.
Every job makes a call to a common webservice by calling its executeMethod with its own user name and password to get medical report associated to a particular user.
The webservice takes time to process a report. So first a job requests for a report and gets a report Id and then the job continuously calls the webservice for retrieving that report every 15 secs till webservice processes the report and the job gets the report.
The issue i am facing is that if there are multiple jobs triggered at the same time then it messes up the username and password.(The above getCurrent() method is called to get the currently executing job)
I am creating a single instance of UserJobExecution for every job. The method jobToBeExecuted is called by the Scheduler for every Job before it is executed.
public class ExecutionJobListener implements JobListener {
public void jobToBeExecuted(JobExecutionContext context){
//Other code
UserJobExecution userJobExecution = new UserJobExecution(job)
userJobExecution.save()
}
//Rest of the code
}
You seem to be using a single instance of UserJobExecution for all the jobs, which leads to a classic synchronization problem. Since all jobs use the same User attribute in the same UserJobExecution instance, several jobs can call getUserFromDB() at the same time, and the user attribute will be overwritten.
Try to build your class so that all jobs do not store the result of getUserFromDB() using a reference that is shared among jobs (e.g. use separate references for each job, by keeping it a local variable for example).
It's not entirely clear from your question what method is scheduled using Quartz Scheduler. Nevertheless I assume that error comes from using ThreadLocal in combination with scheduler. Quartz Scheduler uses internal thread pool to run jobs. When job is called you can't be sure which thread of the pool it is called from. It can be the same thread or any other thread. Consider using JobDataMap to store job state.
Related
I am new to Spring Boot and just implemented a normal Spring Boot application with HTTP where endpoints receive data and put in a database. Now I want some data to put in both databases and a class with data structure. Since there will be continuous operations with this data I need to operate with it as a separate process.
#Service
public class RulesManager {
private HashMap<Integer, Rule> rules = new HashMap<Integer, Rule>();
public void addRule(Rule rule) {
// Add rule to the database
}
// should be running in the background
public void updateRules(){
// Continuous check of rules and update of this.rules HashMap
}
}
#SpringBootApplication
public class RulesApplication {
public static void main(String... args) {
SpringApplication.run(RulesApplication.class, args);
// How do I call RulesManager.updateRules() to run in the background and make changes to rules hashmap???
}
}
So while listening to HTTP requests I want my application to run background process which will never stop and repeat itself. I am not sure how to call that class from the main RulesApplication class so that both http requests and background process were able to make changes to this.rules HashMap. Will be grateful for any tip or advice.
If you are just looking to start a always on process when app starts ( even better when RuleManager gets initialized ), then you should simply create a new thread in the constructor of RuleManager :
methodCalledByConstructor()
{
new Thread(()->{
// loop start
// access and check the hashmap
// do what is necessary
// sleep for a sometime
// loop end
}).start();
}
But if the work is only required when some event occurs, then use observer pattern for more elegant solution.
Try to define a new Thread for example "LocalRulesHandling" and annotate it with #Component and inside this thread add your implementations regarding the rules hashmap.
In the RulesApplication class try to get the spring context and the get the execution thread bean and then start this thread.
ApplicationContext conttext = SpringApplication.run(RulesApplication.class, args);
LocalRulesHandling handling = context.getBean(LocalRulesHandling.class);
handling.start();
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();
}
}
I'm new in spring. Please help me to understand what I have to use (TaskExecutor, #Sceduled,Quarts Sceduler,...) to implement this problem:
I have an Order object and Contacts (connected with 1:N relationship. One Order can have many Contacts). So
When Order is created, application have to send email to all connected Contacts.
When new Contact lately is created and connected to the already created Order, this Contact also have to get an email.
When Order will expire , 2 days later Contact have to get an email.
Step1:
When Order is created, application have to send email to all connected Contacts.
Add 2 new columns into Contacts Table ( or similar table).
is_Send_Email -> boolean type
Email_Send_Time -> timestamp/date type
While inserting a new row ( new order is created), set is_Send_Email=true and Email_Send_Time = current time. for all related Contacts.
2.When new Contact lately is created and connected to the already created Order, this Contact also have to get an email.
When adding a contact to the Order,set is_Send_Email=true and Email_Send_Time = Current time (while inserting) for newly added Contacts.
3.When Order will expire , 2 days later Contact have to get an email.
Set is_Send_Email=true for all contacts in that expiring order and Email_Send_Time = Current time+2 days.
Step2:
Enable scheduling using #EnableScheduling in your configuration class.
#Configuration
#EnableScheduling
public class AppConfig {
#Bean
public MyBean bean() {
return new MyBean();
}
}
Step3:
Use #Scheduled annotation to call your mail sending method at specific intervals.
As per Spring documentation..
34.4.2 The #Scheduled Annotation
The #Scheduled annotation can be added to a method along with trigger
metadata.
For example, the following method would be invoked every 5
seconds with a fixed delay, meaning that the period will be measured
from the completion time of each preceding invocation.
#Scheduled(fixedDelay=5000) public void doSomething() {
// something that should execute periodically
}
If a fixed rate execution is desired, simply change the property name
specified within the annotation. The following would be executed every
5 seconds measured between the successive start times of each
invocation.
#Scheduled(fixedRate=5000) public void doSomething() {
// something that should execute periodically
}
For fixed-delay and fixed-rate tasks, an initial delay may be
specified indicating the number of milliseconds to wait before the
first execution of the method.
#Scheduled(initialDelay=1000, fixedRate=5000) public void
doSomething() {
// something that should execute periodically
}
If simple periodic scheduling is not expressive enough, then a cron
expression may be provided. For example, the following will only
execute on weekdays.
#Scheduled(cron="*/5 * * * * MON-FRI") public void doSomething() {
// something that should execute on weekdays only
}
[Tip] You can additionally use the zone attribute to specify the time
zone in which
the cron expression will be resolved. Notice that the methods to be
scheduled must have void returns and must not expect any arguments. If
the method needs to interact with other objects from the Application
Context, then those would typically have been provided through
dependency injection.
Step4:
Check each record in Order table, if is_Send_Email=true for an record, then trigger email for that Order/Contacts whatever.
How to send email using Spring , You can refer this article.
Happy Learning :-)
I have looked around and around for this answer, but I have not been able to find a good answer. I would like to create a system based on Quartz that allows people to schedule their own tasks. I will use a pseudo example.
Let's say my main method for my Quartz program is called quartz.java.
Then I have a file called sweep.java that implements the Quartz "job" interface.
So in my quartz.java, I schedule my sweep.java to run every hour. I run quartz.java, and it works fine. GREAT; however, now I want to add a dust.java to the quartz scheduler; however, since this is a production service, I don't want to have to stop my quartz.java file, add in my dust.java, and recompile and run quartz.java again. This downtime would be unacceptable.
Does anyone have any ideas on how I could accomplish this? It seems impossible because how could you ever feed another java file into the program without recompiling, linking, etc.
I hope that this example is clear. Please let me know if I need to clarify any part of it.
Partial answer: it is possible to compile, and then instantiate, a class, programatically.
Here are links to example code:
how to compile from a String;
CompilerOutput;
CompilerOutputDirectory.
The extracted class is grabbed in the third source file (see method getGeneratedClass, which returns a Class<?> object).
HOWEVER: keep in mind that this is potentially dangerous to do so. One problem, which can be quite serious if you are not careful, is that when you dynamically instantiate a class, its static initialization blocks are executed. And these can potentially wreak havoc on your application. So, in addition, you'll have to create an appropriate SecurityContext.
In the code above, I actually only ever get the Class<?> object and never instantiate it in any way, so no code is executed. But your usage scenario is quite different.
I have not tried any of these but are worth trying .
1) Consider using Quartz camel endpoint .
If my understanding is right, Apache Camel lets you create the camel routes on the fly.
It just needs to deploy the camel-context.xml into a container taking into consideration that the required classes would be already available on classpath of container.
2) Quartz lets you create a job declaratively i.e. with xml configuration of job and trigger.
You can find more information here.
3) Now this requires some efforts ;-)
Create an interface which has a method which you will execute as a part of job. Lets say this will have a method called
public interface MyDynamicJob
{
public void executeThisAsPartOfJob();
}
Create your instances of Job methods.
public EmailJob implements MyDynamicJob
{
#Override
public void executeThisAsPartOfJob()
{
System.out.println("Sending Email");
}
}
Now in your main scheduler engine, use the Observer pattern to store/initiate the job dynamically.
Something like,
HashMap jobs=new HashMap<String,MyDynamicJob>();
// call this method to add the job dynamically.
// If you add a job after the scheduler engine started , find a way here how to reiterate over this map without shutting down the scheduler :-).
public void addJob(String someJobName,MyDynamicJob job)
{
jobs.add(someJobName,job);
}
public void initiateScheduler()
{
// Iterate over the jobs map to get all registered jobs. Create
// Create JobDetail instances dynamically for each job Entry. add your custom job class as a part of job data map.
Job jd1=JobBuilder.newJob(GenericJob.class)
.withIdentity("FirstJob", "First Group").build();
Map jobDataMap=jd1.getJobDataMap();
jobDataMap.put("dynamicjob", jobs.get("dynamicjob1"));
}
public class GenericJob implements Job {
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.println("Executing job");
Map jdm=arg0.getJobDetail().getJobDataMap();
MyDynamicJob mdj=jdm.get("dynamicjob");
// Now execute your custom job method here.
mdj.executeThisAsPartOfJob();
System.out.println("Job Execution complete");
}
}
I have a singleton class in my play app. This singleton class is a long process which will generate reports from DB which consumes huge amount of memory. When i run my application in dev mode this singleton functionality is executing several times. I want this functionality to run only once. What should I do for that?
My code is:
public class DataGridManagerImpl extends ComponentContainer implements DataGridManager {
private static DataGridManager instance = null;
private DataGridManagerImpl(){
load();
}}
#Override
public void load() {
//Myreports function
}
public static DataGridManager getInstance(){
if (instance == null){
instance = new DataGridServiceManagerImpl();
}
return instance;
}
}
In my controller file inside a template function
DataGridManager dataGridMgr = DataGridManagerImpl.getInstance();
If i access the page it is executing the load reports function again.
Without code explaining how did you create your class it's hard to answer. From what I understand what you want is to run a process only once.
Problably the best approach is to use a Scheduled Job. This will trigger the process at a certain time, and Play ensures that only 1 instance of this process is running at the same time, even if the schedule would indicate another instance has to run. Let's say you have a process scheduled every hour and the process takes 3 hours. The initial process will be the only one running for 3 hours until it finishes.
Now, I would assume you want your process to be recurring as it generate reports. If not, if you only want to run it once, then you may want to use an asynchronous bootstrap job instead. This would run just once, at the beginning of the application.
EDIT on update: during development the #OnApplicationStart may execute several times, as Play may automatically reload the application when you do certain code changes. This is part of the dev process (the same that an #OnApplicationStart job won't start in Dev until the server gets a request).
As it's a job that you only want to run once, you may try to skip it in dev mode using the check:
if(Play.mode == Play.Mode.DEV)
If you need to run it at least once, add a dev-only url that you can access during dev to start the process.
Now, on your update you also mention that you are calling that code in a controller, and that every time the controller is acessed the method is called. That's expected. Singleton doesn't mean that it will run only once, but that there is only 1 object in the system. If in your controller you launch the calculation, that will happen everytime you access the controller.
SECOND EDIT (on comments): Arasu, the other issue is that you are calling the method load() when you construct the object. A singleton doesn't garantee that the object will only be constructed once. It garantees that, once constructed, only 1 object will exist. But it may happen that the object is removed by GC, in this case as per your code if you construct it again then you'll call load() and redo the processing.
The best solution is to not call "load" on constructor, but to force the user (you) to call it after retrieving the instance. An alternative is to set some flag at the beginning of load that detects if the code has been run. Be aware that Play is stateless, so that flag will need to be stored in the database.
the defition of a singleton is that it can run only once, it's practically the nature of the pattern. If you somehow manage to run it multiple times, you might have implementation errors in your singleton.
Recheck the singleton pattern in Wikipedia.
Edit:
This code makes it impossible to fetch more than one instance. How would you get more than one?
public class Singleton {
private static Singleton _instance;
private Singleton() { }
public static synchronized Singleton getInstance() {
if (null == _instance) {
_instance = new Singleton();
}
return _instance;
}
}
Or do you mean that you instanciate the Singleton class, instead of calling Singleton.getInstance()?
It is possible to have a Singleton doing a time consuming processing and be called the same time by two different threads. I think this is the situation here. The same Singleton object's method is called multiple times from the program.
I have run a little test... two thread calling the same Singleton object and here is the result
Thread[Thread 1,5,main] internal loop number = 0 Object = example.Singeton#164f1d0d
Thread[Thread 2,5,main] internal loop number = 0 Object = example.Singeton#164f1d0d
Thread[Thread 1,5,main] internal loop number = 1 Object = example.Singeton#164f1d0d
and here is the code.
package example;
public class Singeton {
private static final Singeton INSTANCE = new Singeton();
private Singeton() {}
public static Singeton getInstance(){
return INSTANCE;
}
public boolean doTimeConsumingThing(){
for (int i=0; i<10000000;i++){
System.out.println(Thread.currentThread() + " internal loop number = " + i + " Object = " + toString());
}
return true;
}
}
package example;
public class MulThread extends Thread{
public MulThread(String name) {
super(name);
}
#Override
public void run() {
while(true){
Singeton s = Singeton.getInstance();
System.out.println("Thread " + getId());
s.doTimeConsumingThing();
}
}
public static void main(String[] args) {
MulThread m1 = new MulThread("Thread 1");
MulThread m2 = new MulThread("Thread 2");
m1.start();
m2.start();
}
}
Please correct my notion above if i am wrong.
Hence what you need is a variable to keep track of the state of the time consuming procedure (i.e. a boolean isRunning) or the times the procedure has been called.
You can also make the pertinent time consuming method of the Singleton synchronized so only one thread can access the method while it is running (in my example if you make the doTimeConsumingThing() synchronized, the second thread will block until the singleton's method called from the first thread is finished.
Hope it helps
I had the same problem in DEV mode, and what I did is create a module for the tasks I don't want to be run at every #OnApplicationStart.
The trick is to launch those tasks in a overriden "onLoad()" method, in the module:
public void onLoad()
{
// tasks to run one time only
}
The onLoad() method is called one time only, not each time the application is restarted.
I don't know if this will help, but here are some things to check:
The code in your question is not thread-safe. You're missing the synchronized keyword in getInstance. That could cause the constructor to be called more than once by different threads.
Could DataGridManagerImpl be getting loaded by different classloaders? That static instance variable isn't static for the whole JVM, just static for that class' classloader.
load is public. Could some other code being calling that method?