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
jhartfieldjhartfield 

Need a way to programatically change or delete a Scheduled Job

Is there any way to change or delete a Scheduled Job ?  I am able to create one easily enough, but once it is made I can only look at the values in the CronTrigger object, but not update them.  Also, it seems I cannot delete them.  I also looked at the System.AbortJob method, but that seems to only stop a job that is already running - I get an error if I try it on a Queued job.

 

The reason I am doing this is to try to create a 'sliding' job.  So, when a trigger is fired the job will run in 5 minutes.  But if the trigger is fired again before that 5 minutes is up, it will find the old job and either delete it and make a new one for 5 minutes out, or update the old one so the next scheduled time is in 5 minutes.

 

Any ideas are welcome!

 

Jason

 

 

Rick_NookIndRick_NookInd

I was surprised at the lack of a system.unschedule

 

I tried system.abortJob but got an error message. 

 

It appears that the name isn't even in CronTrigger so I don't believe you can even see if the scheduled apex is already scheduled unless you use an oddball CronExpression and assume no one ever will use that same oddball CronExpression.  In my case, I need to schedule a job, but only if it isn't already scheduled.

 

I tried just inserting it each time inside a try catch, and apparently I couldn't even catch the system.exception thrown when scheduling apex with the same name?  Sorta weird....

 

ca_peterson_oldca_peterson_old

There doesn't seem to be any way at all to tell what class is being executes. I'd love to be able to even just tell the namespace so I could make sure I'm not deleting jobs I didn't create from the CronTrigger table.

 

Salesforce, help, let me see the job name OR the id of the class being executed OR the namespace. Please?

hemmhemm

To abort a job you need to use the job ID from the CronTrigger table. After I schedule my job, I store this ID in a multi-purpose custom setting object I call Settings.

 

My abort method:

 

// Unschedule all existing jobs

public static void unscheduleApexJobs(){ Settings__c s = Settings__c.getOrgDefaults(); if (s != null){ try{ if (s.Schedule_ID__c != '' && s.Schedule_ID__c != null){ system.abortJob(s.Schedule_ID__c); } } catch (Exception e){ // let it go b/c the job isn't scheduled } } }

 


 Hope that helps.

 

Krishna Prasad K PKrishna Prasad K P

So Does it mean that we can schedule an apex job through SFDC UI but we CANNOT unschedule it through SFDC UI?

Do we need to depend on the Apex code for deleting the scheduled job?

 

Please let me know.

Thanks,

KP

ChrisparxChrisparx

 


hemm wrote:

To abort a job you need to use the job ID from the CronTrigger table. After I schedule my job, I store this ID in a multi-purpose custom setting object I call Settings.

 

My abort method:

 

// Unschedule all existing jobs

public static void unscheduleApexJobs(){ Settings__c s = Settings__c.getOrgDefaults(); if (s != null){ try{ if (s.Schedule_ID__c != '' && s.Schedule_ID__c != null){ system.abortJob(s.Schedule_ID__c); } } catch (Exception e){ // let it go b/c the job isn't scheduled } } }

 


 Hope that helps.

 



 

 

 

 

I do something really close of your solution, storing the id in a table and I retrieve the ID at the next job.

 

The problem is that my system.abortjob(myId) runs without any problem, no exception, ... but the job is not removed !

Am I doing something wrong ??

hemmhemm

It definitely removes it for me.  I just use that one system.abort line

hemmhemm

There is a Monitoring | Scheduled Jobs screen where you can manually abort a schedule after you create one.  There is a UI to do scheduling, but Apex allows for much greater flexibility.  For example, in the UI, I an only run something daily, whereas via Apex I could run something every minute if I wanted to.

ChrisparxChrisparx
if I use the id of the scheduled job and do that in the debug window (system.abortJob(myID)), it works but if I do it in my execute method of the Schedulable class, I don't get any exception when I check the result in the monitoring but I see always the job in the queue ... and after 10, I get the exception. I do my update as well every minute, everything is working fine except the system.abortJob which seems to be totally ignored in my apex class.
ChrisparxChrisparx

Well I got it working. It's not really nice but it works, i did the following:

 

 

       list<CronTrigger> cron = new list<CronTrigger>([select Id, State from CronTrigger]);
       for(CronTrigger CT:cron){
        System.debug('cron trigger ID !!' + CT.Id + ' ' + CT.State);
       }
       for(CronTrigger CT:cron){
  System.abortjob(CT.Id);
       }

 

list<CronTrigger> cron = new list<CronTrigger>([select Id, State from CronTrigger]);      

for(CronTrigger CT:cron){   System.abortjob(CT.Id);        }

 

The problem I think was I tried to remove Cron job with a State = "Waiting". But even now, when I see my queue list, I still have always the oldest job which has a state of "waiting" although he is finished a long time ago and I have a second job which is the latest one. For this one, that makes sense but for the oldest one, I don't really understand... anyway

hemmhemm

Just out of curiosity, why are you unscheduling something inside the schedulable class?  Are you scheduling a job to unschedule jobs?  If so, you probably cannot unschedule the job that you are running at that moment and that's why one is left over.  Seems a little odd, but let me know if I am just understanding.

 

The content of the schedulable class should only be to execute what you want executed on a schedule.  e.g. close old opportunities that were never closed, but should have been.

 

Another piece of code sets the schedule.  Once you run this, your schedule is setup and you leave it alone.  It will kick off when it is supposed to.  Then you just sit back, relax and watch it work for you.

 

If you ever want to unschedule it, then you can call system.abort() in a normal method.  I wouldn't call the system.abort() method inside of the scheduleable class. I've never tried, but I could imagine a case where the system is unable to abort a schedule when it's job is currently running.

Kirk F.ax361Kirk F.ax361

>>>

Just out of curiosity, why are you unscheduling something inside the schedulable class?

<<<

 

He may be trying to implement this code:

http://community.salesforce.com/t5/Apex-Code-Development/How-to-create-a-Schedule-Job-which-runs-after-specific-interval/m-p/178565

 

Which looks promising, but (as it exists) will fail after the 10th self-scheduled run.  It successfully creates new schedule entries, but does not delete the old ones.

hemmhemm

 


Kirk F wrote:

 

He may be trying to implement this code:

http://community.salesforce.com/t5/Apex-Code-Development/How-to-create-a-Schedule-Job-which-runs-after-specific-interval/m-p/178565

 

Which looks promising, but (as it exists) will fail after the 10th self-scheduled run.  It successfully creates new schedule entries, but does not delete the old ones.


 

 

I am still not getting it.  It's too recursive.  You don't need to call system.schedule inside the class you are scheduling.  The class you are scheduling should contain the logic you want run (e.g. kick off a batch job, update some data, etc.)

 

To schedule a job to run every minute, outside of the class you'd run this:

 

id sch = system.schedule('My Sample Schedule','0 * * * * ? *', new myScheduleableClass());

 

The expresstion '0 * * * * ? *' should schedule the job to run every minute.  So you only have 1 schedule in the crontrigger table.  The expression works like this:

 

 

  • 0 = at the 0 second mark
  • * = every minute
  • * = every hour
  • * = every day of the month
  • * = every month
  • ? = ignore the days of the week because we already scheduled it to run every day
  • * = every year

 

 

SidMSidM

Actually, the example you gave won't work as you cannot use the '*' wildcard in schedule timings for seconds and minutes on Force.com. All values must be integers. They have done this to prevent this you scheduling more frequently than every hour.

hemmhemm

Got it.  My most often occurring job is every hour, so I never had to deal with trying to go more often. I wasn't aware of that nuance.  Regardless, I still don't think it makes sense to schedule something inside the class you are scheduling.

 

Not sure if it would work, but another approach I can think of would be to use timed workflow to send an email to an email service 5 minutes after the record is saved. The email service would have the stuff you need to process.  If timed workflow can send this email and it can be caught by an email services, then this would replace your need for an Apex trigger or a schedule.  Kind of a hack and it's just a theory right now, but worth some time investigating.

SidMSidM

Our approach with clients to date is that, if they need to schedule Apex more frequently than the SFDC approach allows, we propose either calling from an external scheduler (so calling an execute method exposed as a web-service from SFDC), or using something such as CronKit (AppExchange app).

 

The other option is that you could set up a Force.com Site to allow any request to a specific page to call the Apex required. The only thing with that is that you'll need to give the various permissions required on each object to the public guest account... not ideal really.

 

CronKit uses workflow and triggers to bypass the 10 schedule limit. The only thing is that you'll then be running your code in the context of a trigger, so much smaller Governor limits than normal Apex execution.

 

Also, there's no guarantee of when a job actually runs - can be up to 15 minutes later than you requested, depending on available platform resources.

hemmhemm

Nice! I forgot about CronKit.  Your approach seems the most robust.

RajitRajit

To delete a scheduled job, which was scheduled by the code itself you need abort the job at the end of the execute method.

like this :

global class testSchedulable implements Schedulable{

global void execute(SchedulableContext sc) {
Database.executebatch(new batchApex_class());
system.abortJob(sc.getTriggerId());
  }

}

 

This will remove the entry of the scheduled job from 'All scheduled jobs'.

 

 

Hope this helps!

 

 

Thanks,

 

Rajit

 

 

 

 

anjs2976anjs2976

Hello,

 

I am having a nearly similar requirement to delete all the completed scheduled jobs (becoz of 10 limit in org) and then kick off a process every n minutes.

 

Somehow I am not getting any job in completed state although some of the jobs have run in past. All the jobs show in Waiting state. 

 

I am stuck so as to how to identify completed jobs and then delete them. Can anybody let me know if I am missing something.

 

Here is the sample code (where i am deleting all jobs which is not right) :

 

List<CronTrigger> completedJobs =[Select c.State, c.EndTime, c.OwnerId, c.Id,c.TimesTriggered, c.NextFireTime,
    c.CronExpression From CronTrigger c ];

 

 //where c.State = 'Completed'
    //where c.EndTime < :currentTime
    
    try{
        System.debug('Scheduled Job Size is ::'+completedJobs.size());
        for(CronTrigger cronJob:completedJobs){
            System.debug(':: Job to Abort::'+String.valueOf(cronJob) + ' c.TimesTriggered ' + cronJob.TimesTriggered
            + ' c.NextFireTime ' +cronJob.NextFireTime);


           // to exclude current job to be deleted

           if(cronJob.Id !=triggerId ) {
                System.abortJob(cronJob.id);
                System.debug(':: Job aborted ::'+String.valueOf(cronJob) );
            }
            else
            {
                System.debug(':: Cannot abort this Job ::'+String.valueOf(cronJob) );
            }
        } 

 

Its urgent so if anybody has any clue please help me out!

 

thanks

Anjali

ChidiChidi

An approach we are looking at is to use the system.abortjob method to removed completed scheduled jobs that have no next run and status = deleted in the CronTrigger sObject.  Adding code like the following in the Schedulable class before other code:

 

  List<CronTrigger> listCronTrigger = [select Id from CronTrigger where State = 'DELETED' and nextfiretime = null];
  If (listCronTrigger.size() > 0)
  {
   For (Integer i = 0; i < listCronTrigger.size(); i++)
   { System.abortJob(listCronTrigger[i].Id); }
  }

SalesForce DummySalesForce Dummy

Thanks. I spent about 2 hours trying to figure this out. I put System.Abort in the execute method and it worked!! Was about to kick my computer!!

SergeyGSergeyG

What about from a trigger? 

System.abortJob doesn't kill the job but works from anonymous... why is that?

 

I'm trying to update a scheduler based on user input (so that they don't have to figure out the cron):

 

State__c configuration = [Select s.Send_Reports__c, s.Run_every_days__c, s.Name, s.Last_Time_Report_Collected__c, s.Id From State__c s limit 1];                List<CronTrigger> ct = [SELECT id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger limit 1];


Integer period = Integer.valueOf(configuration.Run_every_days__c);       

String cron = '0 00 00 */' + period + ' * ?';               

 

if (!ct.isEmpty()){            System.abortJob(ct.get(0).id);        }           

 

if (configuration.Send_Reports__c)           

System.schedule('Email Schedule', cron, new EmailScheduler());      

Radical_arjoRadical_arjo

I am facing the same. problem. Were you able to solve this issue?