I am using Quartz job scheduler for running some jobs. Using java api I am managing the job.
When I reschedule a job to different time using java,
scheduler.deleteJob(jobName, jobGroupName);
addJobsInScheduler(jobName, jobGroupName, triggerName,
triggerGroup, newTime, schoolName);
The job is getting rescheduled and triggered at the specified time.
Now have a requirement in which I have to reschedule the job without UI(without Java api).
From my understanding when I reschedule a job the following table entries getting updated.
QRTZ_JOB_DETAILS
QRTZ_TRIGGERS
QRTZ_CRON_TRIGGERS
So I manually updated the fire time in QRTZ_TRIGGERS,QRTZ_CRON_TRIGGERS. But the job is not triggered at the updated time.
Is that possible to achieve my requirement?
Note: I am using sql server 2008 for my backend.
I believe you shouldn't update the Quartz tables directly with SQL. There are no right way with SQL in Quartz documents so that, no one guarantee not to have any changes for the interface between Quartz and database in the future.
According to the documents Lesson 9: Job Stores
Never use a JobStore instance directly in your code. For some reason
many people attempt to do this. The JobStore is for behind-the-scenes
use of Quartz itself. You have to tell Quartz (through configuration)
which JobStore to use, but then you should only work with the
Scheduler interface in your code.
You should follow the below document for updating your triggers.
How-To: Updating a trigger
If you have no UI, You need to create new interface for updating your schedules somehow.
From experienced, we just update the NEXT_FIRE_TIME column like this:
`UPDATE dbo.QRTZ_TRIGGERS SET NEXT_FIRE_TIME =1491004800 `
where 1491004800 is 1st of April 2017 00:00:00 GMT
Use the T-SQL below to get the NEXT_FIRE_TIME you desire. You may need to change the GETUTCDATE().
SELECT DATEDIFF(s, '1970-01-01 00:00:00', GETUTCDATE())
Then update the QRTZ_CRON_TRIGGERS table
UPDATE dbo.QRTZ_CRON_TRIGGERS set CRON_EXPRESSION='00 10 11 ? * *'
where '00 10 11 ? * *' is run 11:10AM daily. You can get the cron expression from CronMaker
This may not be the best practice but from experience it works for us without issues. I would highly recommend to TEST it first in your lower environment. Wait for the job to trigger and see if you see any changes on the QRTZ_TRIGGERS table.
Related
I wanted to know how does Quartz ensure that only one node in the cluster run a particular job. I know it can be done by setting some properties in quartz.properties like JobStoreTX ,etc, but what is the internal implementation that supports it?
The Clustering in the quartz is done using the database ,so if your job store is JdbcJobStore then the clustering will happen.
Only the scheduler with the same schedule name and distinct instance_name will participate and form a cluster.
1 ClusterManager thread will be used to manage the cluster.This thread ensure that the lastcheckin time is updated at a set interval.If there is any mismatch in that set interval the instance is deemed to be down.
2 Quartz use the standardlocksemaphore for database level clustering of quartz instance
StdRowLockSemaphore
In this class quartz takes a pessimist lock on the row using the
select * from {}_Lock for update
If you check JobStoreSupport class after completing the trigger firing the row lock will be released by completing the transaction.
So if two scheduler instances will complete for the same trigger then only one will be able to succeed.
Hope this helps you in connecting the dots.
I have an UI Interface where user can define Job name, interval, active/Inactive etc.
How we can achieve this with Quartz Scheduler or any java/Spring api ?
Ex. Suppose any Quartz job is started and interval is set as 10 min, So in ideal case job will run in next 10 min interval. But every time job runs we want to fetch the latest interval from database and schedule it.
10:00 Job runs and in the database interval is set to 10 min
10:10 Job runs and in the database interval is set to 20 min
So next time job should run at 10:30
If you use Quartz, you can implement a custom Trigger. Your implementation would lookup the value in the database and return when the next time the run should happen in the getFireTimeAfter.
Another option is to use Spring Scheduling APIs and implement the Trigger interface. Same here, the nextExecutionTime method would decide when the next run should happen.
The advantage of using a custom implementation is that you have full control over the triggering logic (like in your case, do a lookup in the database and dynamically set the next run time).
I want to delete records from MySQL table which were not updated for longer than 3 minutes. How can I set the timer in the background to manage it without being invoked by events or methods in java? Is that possible?
DELETE FROM bus WHERE created_at < (NOW() - INTERVAL 5 MINUTE)
As #abhishek-ghosh correctly pointed out, you can use CREATE EVENT.
CREATE EVENT event_bus_delete
EVERY 5 MINUTE
DO
DELETE FROM bus WHERE created_at < (NOW() - INTERVAL 5 MINUTE);
Event support was added in MySQL 5.1.6. However MySQL Event Scheduler is not running by default and needs to be enabled in order for events to work.
See this StackOverflow answer or How to Configure MySQL Event Scheduler article on how to enable MySQL Event Scheduler and make sure it's running.
You can ensure the scheduler starts when MySQL is launched with the command-line option --event-scheduler=ON or setting event_scheduler=ON in your MySQL configuration file (my.cnf or my.ini on Windows).
Alternatively, you can start the scheduler from the MySQL command line:
SET GLOBAL event_scheduler = ON;
Edit
Misread your question - the following describes how you can use Java to schedule the task rather than doing it independently of the Java layer
You can achieve this by using a combination of Timer and TimerTask. Together they form quite a simple scheduling facility. The Timer schedules TimerTasks that occur periodically.
There are a number of good tutorials on the web : for example
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.
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.