Implementing scheduler in spring (defined by user) - java

I am developing spring mvc application.
I have gone through below links
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-scheduled
http://www.mkyong.com/spring-batch/spring-batch-and-spring-taskscheduler-example/
These guide for how to schedule.
But I have to give it to the users, to schedule(run on daily/weekly basis etc.) some functionality from GUI.
Can any one please help me how can I achieve this?

Suppose you have several tasks to be scheduled by user.
Define a Enum for the tasks names and a Runner to run task by enum. Define a job to be executed every second (minute, hour). The job just checks whether there is a user's task to be executed.
Now user defines such a task whith following params
TaskType (the Enum value)
TaskTime (when it should be started e.g. 12:00)
TaskPeriod (how often it should be called)
TaskTime and TaskPeriod could be joined e.g. in cron expression.
Then all the task info is stored somewhere (e.g. in DB).
Your permanent Job every second reads from the DB whether there is a task to be executed. It checks task time and task period and compares with current time. If it's time to start it gets enum value and calls Runner's method for the enum.

Please check the link. It explains how to schedule tasks by giving crone expressions in a property file.
Other solution is using the quartz library directly. We can schedule or reschedule jobs easily using that. Refer this.
Hope this will help.

Related

Perform an action on an entity after a fixed time

In my Spring project, I have an entity Customer.
Now once we get a new Customer, we persist it in our system, and exactly after one hour, I want to check if the Customer has made any purchase.
If yes, I take some action. If no, the some other.
I contemplated two strategies,
1) Firing up an event when the Customer is persisted. And then having the event listener thread sleep for one hour. I believe this will be a very bad way to handle this.
2) Having a cron check every once in a while for customers for whom one hour has passed since registration. But then, I figure it will be very difficult to be accurate. I would have to run the cron every minute which won't be great.
Any ideas?
You could use the 'ScheduledThreadPoolExecutor' which as per javadoc is:
A ThreadPoolExecutor that can additionally schedule commands to run after a given delay, or to execute periodically
In your case, when a customer is created, you can use the 'schedule' method to wake up after 1 hour and then perform required activities. This method can also be used if you want those activities to be executed periodically as well.
I believe run the cron every minute is not that bad, how many customers would you handle in one minute?
Although not sure why you cannot use the event when a registered Customer will make any purchase i.e. when a particular registered customer will make purchase you can take the action inline as and then.
You described 2 strategies both will work but I would prefer to run cron job which you can configure explicitly. In that way you avoid the overhead of maintaining the threads. If you configure the cron job timing correctly and allow a single job to run at a time I do not see any problem with that. Remember cron jobs are used for batch processing rather than handling events.

How to set to a QUARTZ JOB to start only when an another JOB finished, stopped?

I have a QUARTZ JOB which is starts every 10 minutes.
If a JOB doesn't finish in 10 minutes, in the next 10th minute another JOB will start.
What I want is: the next JOB (after every 10 minute) should start only, if the previous JOB has finished running. Is there any way to do it?
Quartz Documentation
#DisallowConcurrentExecution is an annotation that can be added to the
Job class that tells Quartz not to execute multiple instances of a
given job definition (that refers to the given job class)
concurrently. Notice the wording there, as it was chosen very
carefully. In the example from the previous section, if
"SalesReportJob" has this annotation, than only one instance of
"SalesReportForJoe" can execute at a given time, but it can execute
concurrently with an instance of "SalesReportForMike". The constraint
is based upon an instance definition (JobDetail), not on instances of
the job class. However, it was decided (during the design of Quartz)
to have the annotation carried on the class itself, because it does
often make a difference to how the class is coded.
If you dont want SalesReportForMike and SalesReportForJoe to run concurrently ,then you can set the scheduler's ThreadPool size to 1. So at any given time only one job will run.
Also take a look at StatefulJob
Take a look at the DisallowConcurrentExecution annotation which will prevent multiple instances of the same job to run at the same time.

Is Spring's built in Scheduler persistent.?

I have run into a case where I have to use a persistent Scheduler, since I have a web application that can crash or close due to some problems and might lose it job details if this happens . I have tried the following:
Use Quartz scheduler:
I used RAMJobStore first, but since it isn't persistent, it wasn't of much help. Can't setup JDBCJobStore because, this will require huge code changes to my existing code base.
In light of such a scenario,
I have the following queries:
If I use Spring's built in #Schedule annotation will my jobs be persistent..? I don't mind if the jobs get scheduled after the application starts. All I want is the jobs to not lose their details and triggers.?
If not, are there any other alternatives that can be followed , keeping in mind that I need to schedule multiple jobs with my scheduler.?
If yes, how can I achieve this.? My triggers are different each job. For e.g I might have a job that is scheduled at 9AM and another at 8.30AM and so on.
If not a scheduler, then can I have a mechanism to handle this.?
One thing, I found is that the documentation for Quartz isn't very descriptive. I mean it's fine for a top level config, but configuring it on your an application is a pain. This is just a side note. Nothing to do with the question.
Appreciate the help. :)
No, Spring's #Schedule-annotation will typically only instruct Spring at what times a certain task should be scheduled to run within the current VM. As far as I know there is not a context for the execution either. The schedule is static.
I had a similar requirement and created db-scheduler (https://github.com/kagkarlsson/db-scheduler), a simple, persistent and cluster-friendly scheduler. It stores the next execution-time in the database, and triggers execution once it is reached.
A very simple example for a RecurringTask without context could look like this:
final RecurringTask myDailyTask = ComposableTask.recurringTask("my-daily-task", Schedules.daily(LocalTime.of(8, 0)),
() -> System.out.println("Executed!"));
final Scheduler scheduler = Scheduler
.create(dataSource)
.startTasks(myDailyTask)
.threads(5)
.build();
scheduler.start();
It will execute the task named my-daily-task at 08:00 every day. It will be scheduled in the database when the scheduler is first started, unless it already exists in the database.
If you want to schedule an ad-hoc task some time in the future with context, you can use the OneTimeTask:
final OneTimeTask oneTimeTask = ComposableTask.onetimeTask("my-onetime-task",
(taskInstance, context) -> System.out.println("One-time task with identifier "+taskInstance.getId()+" executed!"));
scheduler.scheduleForExecution(LocalDateTime.now().plusDays(1), oneTimeTask.instance("1001"));
See the example above. Any number of tasks can be scheduled, as long as task-name and instanceIdentifier is unique.
#Schedule has nothing to do with the actual executor. The default java executors aren't persistent (maybe there are some app-server specific ones that are), if you want persistence you have to use Quartz for job execution.

How to do “sequential” Job Scheduling (Quartz?)

I'm making use of Quartz Scheduling and there are 2 jobs. First Job is performing the tasks for around 2 minutes and the Second one is to be setup for Cleaning Operations of Temporary Files. So, I need to setup the Schedule to work in a way that after the first job is executed/finished performing tasks I need to do the cleaning operations with the help of Second Job.
Considering the Example 9 - Job Listeners under Quartz 2.1.x which states that we can define a method named jobWasExecuted( _, _ ); in the Job Listener and it executes when the 1st job is executed/or comes in running state.
Are we able to setup the schedule which can listen for the first job finishing then executes second? or,
Are we able to define the join() method like in Java Multithreading which can execute on the completion of first job?
There currently is no "direct" or "free" way to chain triggers with
Quartz. However there are several ways you can accomplish it without
much effort. Below is an outline of a couple approaches:
One way is to use a listener (i.e. a TriggerListener, JobListener or
SchedulerListener) that can notice the completion of a job/trigger and
then immediately schedule a new trigger to fire. This approach can get
a bit involved, since you'll have to inform the listener which job
follows which - and you may need to worry about persistence of this
information.
Another way is to build a Job that contains within its JobDataMap the name of the next job to fire, and as the job completes (the last step in its Execute() method) have the job schedule the next job. Several people are doing this and have had good luck. Most have made a base (abstract) class that is a Job that knows how to get the job name and group out of the JobDataMap using special keys (constants) and contains code to schedule the identified job. Then
they simply make extensions of this class that included the additional
work the job should do.
Ref: http://www.quartz-scheduler.net/documentation/faq.html#how-do-i-chain-job-execution?-or,-how-do-i-create-a-workflow?
I know this is an old question, but nevertheless there are 2 more options available to chain the execution of your jobs which people can find useful:
1) Use the JobChainingJobListener that is included in the standard Quartz distribution since very early releases. This listener allows you to programmatically define simple job chains using its addJobChainLink method.
2) Use a commercial solution such as QuartzDesk that I am the principal developer of. QuartzDesk contains a robust job chaining engine that allows you to externalize the definition of your job chains from the application code and enables you to update your job chains at runtime through a GUI without modifying, redeploying and restarting your application. A job chain can be associated with a particular job, trigger or it can be a global job chain that is executed whenever any of your jobs execute (useful for global job execution failure handlers etc.).
From http://www.quartz-scheduler.net/documentation/faq.html#how-do-i-chain-job-execution?-or,-how-do-i-create-a-workflow
How do I keep a Job from firing concurrently?
Quartz.NET 2.x
Implement IJob and also decorate your job class with
[DisallowConcurrentExecution] attribute. Read the API documentation
for DisallowConcurrentExecutionAttribute for more information.
The annotation is available in the Java implementation.

Adding a trigger in Quartz scheduler for future use

Quartz API provide a way in which i can create a Job and add it to scheduler for future use by doing something like
SchdularFactory.getSchedulerInstance().addJob(jobDetail, false);
This provides me the flexibility to create jobs store them with the scheduler and use them in later stage.
i am wondering is there any way i can create triggers and add them to scheduler to be used in future.
Not sure if this is valid requirement but if its not possible than all i have to do is to associate the Trigger with any given/existing Job
In Quartz there is a one-to-many relationship between jobs and triggers, which is understandable: one job can be run by several different triggers but one trigger can only run a single job. If you need to run several jobs, create one composite job that runs these jobs manually.
Back to your question. Creating a job without associated triggers is a valid use-case: you have a piece of logic and later you will attach one or more triggers to execute it at different points in time.
The opposite situation is weird - you want to create a trigger that will run something at a given time, but you don't know yet what. I can't imagine use-case for that.
Note that you can create a trigger for future use (with next fire time far in the future), but it must have a job attached.
Finally, check out How-To: Storing a Job for Later Use in the official documentation.

Categories

Resources