7

I had a batch job that I tried to start. Its "startup" method that launches it checks to see if it's already running by querying the asyncjob object, then starts it only if it's not running already AND not scheduled.

After passing those checks, it schedules the job. Here I was getting the error saying that the job with that name was already scheduled.

This happened consistently, but neither the "scheduled jobs" page in the UI menu nor a query could find the job.

To get it to run, I had to switch the name of the job to something else.

I opened a case but have heard nothing of use.

Here's where I look for scheduled jobs (finds none) and proceeds to try to schedule it.

List<CronTrigger> jobs = [SELECT Id, CronJobDetail.Name, State, NextFireTime
                              FROM CronTrigger where CronJobDetail.Name='async_example_schedule2'];

and here's where I schedule it

try{
    System.schedule('async_example_schedule2', 
GetSchedulerExpression(DateTime.Now().addSeconds(3)), 
new ScheduledDispatcher());
}catch (exception e){//fail silently}

Anyone seen this before? I used this batch as an endless loop, so it's very important that it stay running.

As an update, the workaround is to rename the job in the apex class. Then it works for for a few weeks until this same thing happens (we're now on async_example_schedule3 :)

1
  • When you query CronTrigger and/or CronJobDetail , what does your SOQL query look like? Commented Apr 7, 2014 at 1:45

3 Answers 3

7

I have seen similar behavior before. I've also run into two related issues when running self-scheduling jobs that run a lot:

  • the "scheduled job" list gets really long even though most jobs in the list have run already
  • a job in State "DELETED" still holds references to the classes, leading to the dreaded "Schedulable class has jobs pending or in progress" error if/when you try to edit classes in the scope of the job.

The last time I encountered this was a while ago, so API changes may have affected behavior since then, but the approach that has worked with us since is:

  • the scheduled job is scheduled under a unique name (I use name + System.currentTimeMillis()).
  • its ID is stored in a custom setting.
  • when attempting to reschedule, we first call abortJob if the job is returned by [select Id, NextFireTime from CronTrigger where Id = :jobId].
  • next, we clear all past jobs by deleting the results of [select Id from CronTrigger where State = 'DELETED' and NextFireTime = null].
  • then we reschedule.

That works for us and has been reliably working for at least a year.

There is another issue you may run into with jobs who run on a one-off (rather than recurring) cron schedule, which is that during major SFDC maint outages/upgrades I've seen what appears to be the symptom of in-progress batch jobs get terminated or not run, leading to a failure to reschedule. To solve that related issue, I'd recommend the approach that Stephen Willcock presented in answer to this question.

1
  • we had something similar for unique naming before--I wonder if there's an unpublished limit to how many jobs can use the exact same name. Commented Apr 22, 2014 at 20:52
3

I started up a Cron job with the following Anon apex:

System.schedule('MyUniqueJobName', '0 0 * * * ?', new ScheduledApexImpl() );

It then showed up in the Cron Jobs.

Select Id,CronJobDetailId,CronJobDetail.Name,NextFireTime,PreviousFireTime,State,StartTime,EndTime,CronExpression,TimeZoneSidKey,OwnerId,TimesTriggered from CronTrigger where CronJobDetail.Name = 'MyUniqueJobName'

CronTrigger by CronJobDetail.Name

I then aborted the existing job with:

System.abortJob('08e700000049UtgAAE');

It no longer appeared in the results of the previous SOQL query and I was able to schedule it again with exactly the same name.

If I tried to schedule the same job name again before aborting it I get the message:

System.AsyncException: The Apex job named "MyUniqueJobName" is already scheduled for execution.

I suspect your code isn't finding the current CronJob by name correctly. Of course, I could be wrong and my simple test isn't replicating the interaction with a batch job. Still, I'd start by checking your SOQL query against the CronTrigger and CronJobDetail objects.

0

If it is still valid I can put my findings as an Answer for the newbies,

Here what you need to do is you have to query CronTrigger with the name you are going to schedule the Batch with the state and in the simple if check you can Abort the Job and Schedule a Batch again with the same Job Name or If you already schedule a Batch with the same name and it's still in the state other than the Delete you can show an Error that we already have a Scheduled for that particular Schedule class. I achieved it like below,

String jobName = 'Process_Service' + startDateDuration.format() + '-' + endDateDuration.format();

    List<CronTrigger> cronList = [SELECT Id, CronJobDetail.Name, State FROM CronTrigger WHERE CronJobDetail.Name =: jobName];

    if (cronList.isEmpty()) {
        Process_SCH ProcessScheduler = new Process_SCH(startDateDuration, endDateDuration, selectedDate);
        String nextFireTime = String.valueOf(selectedDate.second()) + ' ' + String.valueOf(selectedDate.minute()) + ' ' + String.valueOf(selectedDate.hour()) + ' ' + String.valueOf(selectedDate.day()) + ' ' + String.valueOf(selectedDate.month()) + '  ? ' + String.valueOf(selectedDate.year());
        System.schedule(jobName, nextFireTime, ProcessScheduler);
        return 'Successfully Start the Job';
    } else if (cronList.size() == 1 && cronList[0].State == 'DELETED') {
        System.abortJob(cronList[0].Id);
        Process_SCH ProcessScheduler = new Process_SCH(startDateDuration, endDateDuration, selectedDate);
        String nextFireTime = String.valueOf(selectedDate.second()) + ' ' + String.valueOf(selectedDate.minute()) + ' ' + String.valueOf(selectedDate.hour()) + ' ' + String.valueOf(selectedDate.day()) + ' ' + String.valueOf(selectedDate.month()) + '  ? ' + String.valueOf(selectedDate.year());
        System.schedule(jobName, nextFireTime, ProcessScheduler);
        return 'Successfully Start the Job';
    } else if (cronList.size() == 1 && cronList[0].State != 'DELETED'){
        return 'The Apex job named " ' + jobName + ' " is already scheduled for execution.';
    }

You have to keep it in mind that if the Scheduled Batch ran successfully then the Job state will changed to DELETE and still it will be in the Job list so you can't create a job with the same job name even if the job completed the Batch run.

What you can do to avoid this is you can check it like above in the code or else you can delete all the older jobs as like below.

Integer count = System.purgeOldAsyncJobs(Date.today());
System.debug('Deleted ' + count + ' old jobs.');

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .