how to prevent quartz from running another job if the previous one is still running? - quarkus

I'm using Quarkus. My Quartz jobs are scheduled to run every 10 seconds:
return TriggerBuilder.newTrigger()
.withIdentity("my-job")
.startNow()
.withSchedule(
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever()
).build();
This works fine but jobs keep triggering every 10 seconds irrespective of whether or not the last one finishes. I need the next job to start only if there are no jobs currently running job. How do I accomplish this?

Add #DisallowConcurrentExecution on you Job class.
as example :
#DisallowConcurrentExecution
public class MyScheduledJob implements Job {
//execution method
}

Related

Keep track of laravel queued jobs

I'm trying to get department details from an API which supports pagination, so if I spawn one job per page like following
/departments?id=1&page=1 -> job1
/departments?id=1page=2 -> job2
How can I keep track of these jobs for a particular department as I have to write the responses to txt file.
The jobs are instantiated via controller class like:
class ParseAllDeptsJob implements ShouldQueue
{
public function handle()
{
foreach (Departments::all() as $dept) {
ParseDeptJob::dispatch($dept);
}
}
}
You can chain a job, using withChain(). This job will not run if the jobs higher up the chain fail.
From the documentation:
Job chaining allows you to specify a list of queued jobs that should
be run in sequence. If one job in the sequence fails, the rest of the
jobs will not be run. To execute a queued job chain, you may use the
withChain method on any of your dispatchable jobs:
In your case, this is how you'd do it:
ParseAllDeptsJob::withChain([
new SendEmailNotification
])->dispatch();
SendEmailNotification won't be dispatched if an error occurs while processing ParseAllDeptsJob.

Spring Scheduler stops working for my cron expression

I've a method scheduled to run periodically with Spring Scheduler, it's been working fine and stopped working today with no error. What could be the potential cause ? Is there any alternative way to schedule task periodically using Spring Scheduler that ensures that the method will be executed no matter what?
#Scheduled(cron="0 0/1 * * * ?")
public void executePollingFlows(){
if(applicationConfig.isScheduleEnabled()) {
for (long flowId : applicationConfig.getPollingFlowIds()) {
flowService.executeFlow(flowId);
}
logger.info("Finished executing all polling flows at {}", new Date());
}
}
You may have got Out of Memory exception if the job could not finish its tasks but you try to run it again and again. If it is a Out of Memory exception you may try to create a ThreadPool and check it in every run. If there is no enough space in the ThreadPool you can skip the task for this turn.
There is alternative way to use #Scheduled periodically. You may change your #Scheduled annotation with this:
#Scheduled(fixedRate=1000)
It will still be running in every second and if necessary you can add initialDelay to it:
#Scheduled(initialDelay=1000, fixedRate=1000)
You can find more details about fixedRate, initialDelay and fixedDelay here:
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html

Reschedule the scheduled task in spring scheduler

I have a Runnable class which is scheduled to run at fixed rate (I am using spring scheduler):
taskScheduler.scheduleAtFixedRate(this, startTime.toDate(),
PERIOD * 1000);
Can I reschedule the task or change the period dynamically after it has been scheduled?
You can probably use the following DynamicPeriodicTrigger https://github.com/spring-projects/spring-integration-samples/blob/master/intermediate/dynamic-poller/src/main/java/org/springframework/integration/samples/poller/DynamicPeriodicTrigger.java
So you have to create a DynamicPeriodicTrigger instance (with fixedRate = true) and put the reference into taskScheduler.schedule(Runnable task, Trigger trigger); method.
You can than dynamically change object attributes, to change execution periods on the fly.

Limit the lifetime of a batch job

Is there a way to limit the lifetime of a running spring-batch job to e.g. 23 hours?
We start a batch job daily by a cron job and he job takes about 9 hours. It happened under some circumstances that the DB connection was so slow that the job took over 60 hours to complete. The problem is that the next job instance gets started by the cronjob the next day - and then anotherone the day after - and anotherone...
If this job is not finished within e.g. 23 hours, I want to terminate it and return an error. Is there a way to do that out-of-the-box with spring-batch?
Using a StepListener you can stop a job by calling StepExecution#setTerminateOnly.
stepBuilderFactory
...
.writer(writer)
.listener(timeoutListener)
...
.build()
And the TimeoutListener could look like this
#Component
public class TimeoutListener implements StepListener {
private StepExecution stepExecution;
#BeforeStep
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
#BeforeRead
public void beforeRead() {
if (jobShouldStop()) {
stepExecution.setTerminateOnly();
}
}
private boolean jobShouldStop() {
// ...
}
}
This will gracefully stop the job, without forcefully terminate any running steps.
Spring Batch specifically avoids the issue of job orchestration which this falls into. That being said, you could add a listener to your job that checks for other instances running and calls stop on them before beginning that one. Not knowing what each job does, I'm not sure how effective that would be, but it should be a start.
If you write your own job class to launch the process you can make your class implement StatefulJob interface, which prevents concurrent launches of the same job. Apart from that you can write your own monitoring and stop the job programatically after some period, but it will require some custom coding, I dont know if there is anything build-in for such use case.

Windows task scheduler to execute tasks in seconds

I'm looking for an open source/free task scheduler for Windows 7 (development machine) that will allow me to schedule tasks (HTTP requests to a web service) to run every x seconds.
I've tried a couple of Cron clones and windows own Task Scheduler but neither seem to allow tasks to run at intervals less than 60 seconds. Am I missing something? I don't want to have to go and write any custom scripts either if possible.
It is possible to create multiple triggers for one scheduled task. If you create 59 identical triggers with an offset of 1 second to each other, and schedule the task itself to run every minute, you end up the scheduled task to run every second.
You could create those 59 triggers manually using the GUI. However, a much quicker way to create so many triggers is to create a task with one or two triggers, export it to a text file, duplicate the according lines, change the start offsets accordingly, and then re-import the file.
I was actually able to achieve this.
Update: Seems I over complicated it.
In the trigger, where it says "Repeat task every:" you can actually TYPE into the drop-down "1 minute" (It wont let you type the time in seconds)
I did this on a Windows 7 machine.
Also, I clearly did not read the question well enough, as the asker seems to already have been able to get the time down to 1 minute. However, I'll leave this answer here, as it will explain for future readers exactly how to get the time down to one minute.
It does seem as though you cannot get it to run at an interval of less than one minute.
I set up a task with a trigger set to Daily to recur every 1 day.
I check the "Repeat task every:" box. Setting it to 5 Minutes for a duration of 1 day
This makes the task go forever, every 5 minutes.
I then exported the task. It exports to a .xml file.
Under Task > Triggers > CalendarTrigger > Repeition there is the following tag: <Interval>PT5M</Interval> I changed it from PT5M to PT1M. I re-imported the task.
The task now runs every 1 minute.
I have not fully tested this, and I have not tried with less than one minute, but it might be possible by putting PT30S or something for 30 seconds. I'll try it out and report back. Update: You cannot do this, you get an error when importing the task. It's not possible to set this time to less than 1 minute.
The whole trigger looks like this for me:
<Triggers>
<CalendarTrigger>
<Repetition>
<Interval>PT1M</Interval>
<Duration>P1D</Duration>
<StopAtDurationEnd>false</StopAtDurationEnd>
</Repetition>
<StartBoundary>2013-11-07T17:04:51.6062297</StartBoundary>
<Enabled>true</Enabled>
<ScheduleByDay>
<DaysInterval>1</DaysInterval>
</ScheduleByDay>
</CalendarTrigger>
</Triggers>
I've googled this to death, so as far as I can see the answer is, there are none. There are plenty of commercial solutions, but no open source/free programs.
I ended up writing a very simple periodic HTTP GET scheduler in java using quartz scheduler. It may be useful to other so posting a link to the source on guthub https://github.com/bjordan/simple_java_periodic_HTTP_scheduler
Short explanation:
Main program starts a service process that will stay active in memory and will periodically activate a job – do something.
Create a class that extends System.ServiceProcess.ServiceBase class
Implement at least methods OnStart and OnStop
Start and use Quartz.NET scheduler in OnStart to run tasks periodically
Here is my template C# solution for a Windows service and a Linux demon in .NET/Mono https://github.com/mchudinov/ServiceDemon
And a short blogpost about it
class Program
{
public static void Main(string[] args)
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new ServiceDemon.Service() };
ServiceBase.Run(ServicesToRun);
}
}
public class Service : ServiceBase
{
static IScheduler Scheduler { get; set; }
protected override void OnStart(string[] args)
{
StartScheduler();
StartMyJob();
}
protected override void OnStop()
{
Scheduler.Shutdown();
}
void StartScheduler()
{
ISchedulerFactory schedFact = new StdSchedulerFactory();
Scheduler = schedFact.GetScheduler();
Scheduler.Start();
}
void StartMyJob()
{
var seconds = Int16.Parse(ConfigurationManager.AppSettings["MyJobSeconds"]);
IJobDetail job = JobBuilder.Create<Jobs.MyJob>()
.WithIdentity("MyJob", "group1")
.UsingJobData("Param1", "Hello MyJob!")
.Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("MyJobTrigger", "group1")
.StartNow()
.WithSimpleSchedule(x => x.WithIntervalInSeconds(seconds).RepeatForever())
.Build();
Scheduler.ScheduleJob(job, trigger);
}
}
public class MyJob : IJob
{
public void Execute(IJobExecutionContext context)
{
JobDataMap dataMap = context.JobDetail.JobDataMap;
log.Info(dataMap["Param1"]);
}
}

Resources