function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
MJ09MJ09 

System.Schedule sometimes schedules a job to run next year

I have a batch Apex job (A) that, upon completion, needs to launch another batch Apex job (B). Since you can't launch a batch Apex job from from a batch Apex job, job A schedules job B to run 2 seconds later. (JobB is both batchable and schedulable. JobB's schedulable execute() method launches the JobB batch job.)

 

Here's the code from job A's finish() method:

 

 

global void finish(Database.BatchableContext bc) {
// Seconds Minutes Hours Day_of_month Month Day_of_week optional_year
String str = Datetime.now().addSeconds(2).format('s m H d M ?');
JobB cls = new JobB();
System.Schedule('Job B', str, cls);
return;
}

 

Most of the time, this works just fine. However, every now and then, instead of being scheduled to run 2 seconds later, JobB gets scheduled to run 1 year later. For example, I'll see a job in the Scheduled Jobs queue that has a Submitted time of "11/10/2010 5:00PM" and a Next Scheduled Run time of "11/10/2011 5:00PM."

 

I just changed my code to wait 10 seconds instead of just 2 seconds to schedule JobB, which will hopefully eliminate the problem. However, I'm left wondering why 2 seconds isn't sufficient. Any thoughts? Has anybody else run into this kind of problem?

 

Best Answer chosen by Admin (Salesforce Developers) 
MJ09MJ09

You'd think that if the date/time string expression that you use to schedule a job doesn't include the "optional year," it would default to the current year. Apparently not.

 

If I change my string expression to include "yyyy,"  it works fine. If I don't include "yyyy," it uses the current year most of the time, except when it decides to use the next year.

 

Here's the string expression that works all the time:

 

 

 String str = Datetime.now().addSeconds(10).format('s m H d M ? yyyy');  

 

 

All Answers

Imran MohammedImran Mohammed

Modify the format and try once.

String str = Datetime.now().addSeconds(2).format('ss mm HH dd MM ? yyyy');

MJ09MJ09

Imran,

 

Thank you for your response!

 

Just wondering -- do you know that two-digit numbers will fix the problem, or are you suggesting that I try it and see? This is such an intermittent problem that it will take us several days or longer to determine whether this change will fix it.

 

For what it's worth, the Apex manual doesn't specifically discuss 2-digit numbers, and it does give an example that doesn't use them:

 

 

scheduledMerge m = new scheduledMerge();
String sch = '20 30 8 10 2 ?';
system.schedule('Merge Job', sch, m);

 

(From p. 79 of the Winter 11 Apex Language Reference.)

 

 

Thanks.

Imran MohammedImran Mohammed

It was a suggestion. I am not sure it will resolve the issue.

I have one question, Are you trying to schedule it every 2 seconds?

One more thing i would like to know is, was the job starting after 2 seconds of submission.

MJ09MJ09

Again, thanks for your reply!

 

Job A runs twice a day, so no, we're not trying to get it to run every 2 seconds. (I have to wonder whether we'd run into any governor limits, trying to have a process run that often!)

 

We have this Job A / Job B thing running in about a dozen customer orgs, and it has run without problems for three or four months. This problem (where instead of being scheduled 2 seconds later, Job B is scheduled one year later) surfaced once, in one org, a few weeks ago. Then it happened twice this week. I don't know whether something changed in Salesforce to make it happen more often, or whether it's happening at random.

 

MJ09MJ09

You'd think that if the date/time string expression that you use to schedule a job doesn't include the "optional year," it would default to the current year. Apparently not.

 

If I change my string expression to include "yyyy,"  it works fine. If I don't include "yyyy," it uses the current year most of the time, except when it decides to use the next year.

 

Here's the string expression that works all the time:

 

 

 String str = Datetime.now().addSeconds(10).format('s m H d M ? yyyy');  

 

 

This was selected as the best answer
Imran MohammedImran Mohammed

Good to see you got it.

My reply was almost similar to the one which you found working.

Thanks for throwing light on the way system does Scheduling.

Its nice to learn such things.

Thanks

symantecAPsymantecAP

Hi All

 

I was going through this post and I have the following code. I want to schedule my class every 15 seconds to update parent object called Opportunity.

 

Do let me know if my code is correct to acheive that.

secondly my batch apex is only processing one record. is there any bug in my code. do let ne know

 

global class updateOpportunityStage implements Database.Batchable<sObject>,Schedulable{
global string query ;

global updateOpportunityStage(){

Query = 'Select Id,BigMachines__Status__c  from BigMachines__Quote__c' ;

}

global database.querylocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);    
}
    global void execute(SchedulableContext SC){
        updateOpportunityStage stg = new updateOpportunityStage();
       String cronStr = '0 0 * 30 * ?n';
        System.schedule('Process Quotes', cronStr, stg);
        database.executebatch(stg);
        
    }

global void execute(Database.BatchableContext BC, List<sObject> scope){

     
        Set<id> liOppIds = new Set<id>();
//List <Opportunity> oppList = new List<Opportunity>() ;
for(sObject s : scope){

BigMachines__Quote__c quote = (BigMachines__Quote__c)s;
// System.debug('Adil'+quote);
if(quote.BigMachines__Status__c == 'unison' && quote.BigMachines__Is_Primary__c == true)
liOppIds.add(quote.BigMachines__Opportunity__c);

}


//query all the opportunities in a single query
List<Opportunity> opp = new List<Opportunity>();
opp = [select id, StageName from Opportunity where id in :liOppIds and stagename != 'Closed Won'];
for ( Opportunity opps : opp)
{
opps.StageName = 'Closed Won' ; 
}
//update all opportunities in a single DML
if(opp.size() > 0)
update opp;
 
    }
  global void finish(Database.BatchableContext BC){}  

}

 Thanks

Adil