We have a Java application (ESB) that uses quartz 2.2.1 and we use it to schedule hundreds of user jobs.
I want to build monitoring page (or scheduler administration page) in my application for our users so that they can see if quartz scheduler is running fine or there is any issue in this component.
Does quartz provides any monitoring API for this purpose? Can anyone please tell us what all data points should we show in this monitoring (or administration) page based on your experience? Some of the points that I can think of:
Scheduler Status (Running | Paused | Shutdown).
Number of jobs running with "Previous Fire Time" and "Next FireTime" information.
Thread pool implementation and its size.
JDBCJobStore configuration details.
Is there a way to show the information about triggers that were misfired? I don't see any API that provides me information about misfired triggers. Can anyone tell me how to get this information from scheduler?
Any help in this regard shall be appreciated.
You named here many different issues
Scheduler Status(1) :
Scheduler sched =...
sched.isInStandbyMode();
sched.isStarted();
sched.isShutdown();
Number of jobs running with...(2) see here
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
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);
}
}
Thread pool implementation and its size.(3)
Scheduler sched =...
sched.getMetaData().getThreadPoolClass()
sched.getMetaData().getThreadPoolSize()
Regarding "triggers that were misfired", you can use listeners, specifically TriggerListener.html#triggerMisfired may be helpful for you.
Related
How does history replay work in cadence?
I have a workflow which calls two activity sequentially.
Say, the first activity got completed and the second has 100 no of lines of code. If the app server restarts when executing the 50th line of the code in activity2, is it exactly starts the execution from the 50th line. If yes, what magic is happening inside cadence?
#Override
public String composeGreeting(String greeting, String name) throws Exception {
FileWriter fw =
new FileWriter(
"/Users/kumble-004/Documents/Uber_Cadence/Sample_Projects/TestCadence/src/com/company/"+name+".txt");
System.out.println(
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now())
+ " [Activity] started");
long time = System.currentTimeMillis() + 240000;
int i = 0, j=1;
while (System.currentTimeMillis() != time) {
if(i++ %10000000 == 0) {
fw.write("print - " + j++ + " " +
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now()) +"\n");
}
}
fw.close();
System.out.println(
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now())
+ " [Activity] ended");
return greeting + " " + name + "!";
}
}
I have the above code in my hello activity. this code will run for 4 minutes and it will be writing data in a file when a condition meets
I started a workflow and have quit the cadence server after printing [Activity] started. I didn't start it just stops it. But after 4 minutes it is exactly printing [Activity] Ended in the console. I am wondering how is this possible because I stop the server but code is executing, data is writtening in file.
While I am checking it via cadence UI it shows that the last history is
ActivityTaskStarted. And I started my server. After 15 mins(beacuse scheduleToCloseTimeoutSeconds is 15 mins) Activity returns with event ActivityTaskTimedOut and the whole whorkflow has failed due to this timeout.
Kindly explain what is happening when restarting cadence server ?
If the app server restarts when executing the 50th line of the code in activity2, is it exactly starts the execution from the 50th line
No, it will not resume from 50th line of activity automatically for you.
Replay is only happening for Workflow. It is relaying on History to replay and rebuild the memory stack. Everything happens in the workflow is stored in the history:
Every step in the workflow code, generates a bunch of results called "Decision"
Activity/ChildWorkflow results
External events like Signals
Timers
Etc.
For more details, please refer to the doc about replay history and What exactly is a Cadence decision task?
But after 4 minutes it is exactly printing [Activity] Ended in the console. I am wondering how is this possible because I stop the server but code is executing, data is writtening in file.
That's because your activity worker is still running. The code you are running is purely activity code.
However, it activity results will not be able reported to server when the server is down. Which means the history will lose it and workflow may reschedule another activity(if retry is enabled).
Please refer to the doc about activity timeout and retry
I need to achieve the ability to monitor and be able to cancel an ALREADY RUNNING job on queue.
There's a lot of answers about deleting QUEUED jobs, but not on an already running one.
This is the situation: I have a "job", which consists of HUNDREDS OF THOUSANDS rows on a database, that need to be queried ONE BY ONE against a web service.
Every row needs to be picked up, queried against a web service, stored the response and its status updated.
I had that already working as a Command (launching from / outputting to console), but now I need to implement queues in order to allow piling up more jobs from more users.
So far I've seen Horizon (which doesn't runs on Windows due to missing process control libs). However, in some demos seen around it lacks (I believe) a couple things I need:
Dynamically configurable timeout (the whole job may take more than 12 hours, depending on the number of rows to process on the selected job)
Ability to CANCEL an ALREADY RUNNING job.
I also considered the option to generate EACH REQUEST as a new job instead of seeing a "job" as the whole collection of rows (this would overcome the timeout thing), but that would give me a Horizon "pending jobs" list of hundreds of thousands of records per job, and that would kill the browser (I know Redis can handle this without itching at all). Further, I guess is not possible to cancel "all jobs belonging to X tag".
I've been thinking about hitting an API route, fire the job and decouple it from the app, but I'm seeing that this requires forking processes.
For the ability to cancel, I would implement a database with job_id, and when the user hits an API to cancel a job, I'd mark it as "halted". On every loop I would check its status and if it finds "halted" then kill itself.
If I've missed any aspect just holler and I'll add it or clarify about it.
So I'm asking for an advice here since I'm new to Laravel: how could I achieve this?
So I finally came up with this (a bit clunky) solution:
In Controller:
public function cancelJob()
{
$jobs = DB::table('jobs')->get();
# I could use a specific ID and user owner filter, etc.
foreach ($jobs as $job) {
DB::table('jobs')->delete($job->id);
}
# This is a file that... well, it's self explaining
touch(base_path(config('files.halt_process_signal')));
return "Job cancelled - It will stop soon";
}
In job class (inside model::chunk() function)
# CHECK FOR HALT SIGNAL AND [OPTIONALLY] STOP THE PROCESS
if ($this->service->shouldHaltProcess()) {
# build stats, do some cleanup, log, etc...
$this->halted = true;
$this->service->stopProcess();
# This FALSE is what it makes the chunk() method to stop looping
return false;
}
In service class:
/**
* Checks the existence of the 'Halt Process Signal' file
*
* #return bool
*/
public function shouldHaltProcess() :bool
{
return file_exists($this->config['files.halt_process_signal']);
}
/**
* Stop the batch process
*
* #return void
*/
public function stopProcess() :void
{
logger()->info("=== HALT PROCESS SIGNAL FOUND - STOPPING THE PROCESS ===");
$this->deleteHaltProcessSignalFile();
return ;
}
It doesn't looks quite elegant, but it works.
I've surfed the whole web and many goes for Horizon or other tools that doesn't fit my case.
If anyone has a better way to achieve this, it's welcome to share.
Laravel queue have 3 important config:
1. retry_after
2. timeout
3. tries
See more: https://laravel.com/docs/5.8/queues
Dynamically configurable timeout (the whole job may take more than 12
hours, depending on the number of rows to process on the selected job)
I think you can config timeout + retry_after about 24h.
Ability to CANCEL an ALREADY RUNNING job.
Delete job in jobs table
Delete process by process id in your server
Hope it help you :)
While building an Atlasboard Job, I would like to control where and when data is pushed to the widget.
I could not find where the "interval" config parameter is documented - my understanding is that the job is scheduled each interval ms.
I would like to take control over when my job updates the widget. I therefore did a small test:
setInterval(function() {
x = x+1;
jobCallback(null, {title: config.widgetTitle + " - "+x});
}, 10000);
At first I was happy as it seem to have worked but than I noticed the log messages:
[dashboard: xxx] [job: xxx] 14:04:27.93 <warn> WARNING!!!!: job_callback executed more than once for job xxx in dashboard xxx (scheduler.js)
[dashboard: xxx] [job: xxx] 14:04:27.96 <warn> WARNING!!!!: job_callback executed more than once for job xxx in dashboard xxx (scheduler.js)
[dashboard: xxx] [job: xxx] 14:04:37.94 <warn> WARNING!!!!: job_callback executed more than once for job xxx in dashboard xxx (scheduler.js)
I might add that after few more minutes the job seem to replicate itself and global parameters seem to not keep their global value between job instances - such that soon after my single 'recurring job' becomes ten jobs, than 100 etc.
Is there a way to gain better control over when the data is pushed to the widget?
Is there better documentation than https://bitbucket.org/atlassian/atlasboard and http://atlasboard.bitbucket.org/ ?
I found out the following during my search and looking into the jobWorker code (I could not find any documentation anywhere).
There is a pushUpdate member function that was added to the jobWorker - it appears as if it is best used during the Job onInit() - in this way we assure that it is activated only once!
onInit: function (config, dependencies) {
var jobWorker = this;
var x = 0;
setInterval(function() {
x = x+1;
jobWorker.pushUnpdate({title: config.widgetTitle + " - "+x);
}, 10000);
}
Note that if you take control over the scheduling of the updates, there is no need to implement a Job onRun() - meaning that no scheduler will be activated for your Job.
I have an asp.net website and want to do a task once a day.
the task is: sending email to users 2 days before expiration of their registration.
I used Quartz.NET version 1.0. I have wrote a sample code that opens a window in each second. Now I don't know where should I locate this code in my asp.net project?! it is now in a simple page. I want it to be independent from pages.
public class DumbJob : IJob
{
public DumbJob()
{
}
public void Execute(JobExecutionContext context)
{
Console.WriteLine("DumbJob is executing.");
System.Windows.Forms.MessageBox.Show("NICE");
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// construct a scheduler factory
ISchedulerFactory schedFact = new StdSchedulerFactory();
// get a scheduler
IScheduler sched = schedFact.GetScheduler();
sched.Start();
// construct job info
JobDetail jobDetail = new JobDetail("myJob", null, typeof(DumbJob));
// fire every hour
Trigger trigger = TriggerUtils.MakeSecondlyTrigger();//.MakeHourlyTrigger();
// start on the next even hour
trigger.StartTimeUtc = TriggerUtils.GetEvenSecondDate(DateTime.UtcNow);
trigger.Name = "myTrigger";
sched.ScheduleJob(jobDetail, trigger);
}
}
There are various ways you can do that...but certainly it's probably better o build some sort of console applications for your case.
Frankly the simplest of which could be a windows schedule task that would trigger every day and launch an exe program (that you'd write using console dotnet) that would check soon-to-expire users and send an email when found...
If you don't want to have user + email code in various places (and centralize all this in your dotnet web app), then I'd create a SOAP/REST end point in your .NET webapp that would be called by a thin client, which would be scheduled by that "windows schedule task"
Quartz would give you more flexibility when it comes to scheduling and doing more enterprise things like job clustering / job high availability / job monitoring for example...
But that'd still be a .NET console app which would start a quartz scheduler, create a trigger, and run forever...(possibly wrapped into a windows "wrapper" service for more control)
I've started using Quartz.NET recently, and so far, it's been really
helpful. Now, I'm trying to use it to create a job that runs once a
month using a NthIncludedDayTrigger (I want to use the
NthIncludedDayTrigger as eventually I will be specifying a calendar to
exclude weekends/holidays).
To familiarise myself with the code, I've
set up a simple console application to create an NthIncludedDayTrigger
where the first fire time will be 15 seconds from now:
static void Main(string[] args)
{
IScheduler scheduler = StdSchedulerFactory.DefaultScheduler;
scheduler.Start();
var jobDetail = new JobDetail("Job name", "Group name", typeof(SomeIJobImplementation));
var trigger = new NthIncludedDayTrigger();
trigger.Name = "Trigger name";
trigger.MisfireInstruction = MisfireInstruction.NthIncludedDayTrigger.DoNothing;
trigger.IntervalType = NthIncludedDayTrigger.IntervalTypeMonthly;
//I'm using the following while experimenting with the code (AddHour(1) to account for BST):
trigger.FireAtTime = DateTime.UtcNow.AddHours(1).AddSeconds(15).ToString("HH:mm:ss");
//I'm using the following while experimenting with the code:
trigger.N = DateTime.Today.Day;
Console.WriteLine("Started, press any key to stop ...");
Console.ReadKey();
scheduler.Shutdown(false);
}
...
public class SomeIJobImplementation : IJob
{
public void Execute(JobExecutionContext context)
{
Logger.Write(String.Format(
"Job executed called at {0}",
DateTime.Now.ToString("dd-MMM-yyyy HH:mm:ss")), null, 1,
TraceEventType.Information);
}
}
Running this results in the job being executed multiple times
(approximately once per second) for one minute. I'm using an ADO.NET
job store and can see in my database that QRTZ_TRIGGERS.NEXT_FIRE_TIME
is set to the last executed time, i.e. doesn't seem to be scheduled to
run again.
I expected the above code to run the job once (after about 15
seconds), then schedule the job to run again in one months time.
Perphaps the issue is just with the way I'm using Quartz.NET whilst
I've been experimenting or, maybe, my expectations are wrong? Either
way, I would be most grateful for any help/suggestions to explain the
behaviour I've observed, and what I need to change to get the
behaviour I want.
I must be late but I was trying to implement the same solution and ended up here.
I reckon you should star the scheduler after you've defined jobs and triggers.