You need to sign in to do that
Don't have an account?

How delete existing Apex Scheduled Jobs from Apex?
I can schedule a job via Apex code:
System.schedule('test', '0 0 0 * * ?', new SchedulableClass());
The CronTrigger job doesn't have a "Name" field, so I can't query for the Job I just created. This means I can't check to see if my job already exists calling System.schedule(); instead I just have to call "schedule()" and silently eat the exception it throws if the job already exists.
The only way you can figure out which CronTrigger is yours is to cache the return value of System.schedule(), which (it so happens) is the ID of the CronTrigger that is created. However, you can't delete them from Apex:
Id jobid = System.schedule('test', '0 0 0 * * ?', new SchedulableClass());
delete new CronTrigger(Id = jobid);
// 'delete' throws 'DML not allowed on CronTrigger'
So the current state of Scheduled Jobs is:
You can create them from Apex Code, but not from the UI
You can delete them from the UI, but not from Apex Code
I guess that just seems odd to me. Why did Salesforce create this whole new API (System.schedule()), with a seemingly random assortment of ways to manipulate it, instead of just exposing the CronTrigger table directly to the full range of DML operations?
Placing new functionality into new core objects, rather than new APIs, seems easier on everyone (the whole describe/global describe suite of API calls are an example of something that seems a natural fit for a set of read-only custom objects).
Id not name:
eg:
String SCHEDULE_NAME = 'test'; id cronid = System.schedule(SCHEDULE_NAME, '0 15 0-23 * * ?', new scheduledMaintenance()); System.abortJob(cronid);
And to schedule via the UI: Navigate to the Apex class list page - select "schedule apex"
let me know if this helps.
t
All Answers
Actually, you can't catch the exception thrown by System.schedule(), so there's no good way to idempotently create a scheduled task.
Thank you for the feedback.
1) You can create Scheduled Jobs from both the UI and Apex
2) You can delete Jobs from the UI or through Apex via System.abort(scheduled job id)
3) We should allow you to catch the exceptions - this looks like an oversight on our end. You can however, query the Crontrigger to programmatically determine the available slots for scheduled jobs.
4) Not exposing the name field is another oversight. I'll log a bug for this. The workaround is to manage the jobs via the ID.
Taggart -
Thanks for the info!
I might not have been clear - I'm looking to un-schedule a job that might not currently be running (ie, a cron job that runs repeatedly via the CronTrigger table). It's my understanding that System.abort() is for a jobs that are currently running (which may have been launched by a CronTrigger).
For example, the following code does not work:
I get this exception on line 3:
System.StringException: Only batch and scheduled jobs are supported.
Also - maybe I'm missing something - but I don't see how to create a Scheduled Job in the UI.
My "Scheduled Jobs" page does not have a "New" button:
The entry in there was placed via Apex Code. The "Del" link above is the only way I know of to delete it.
Id not name:
eg:
String SCHEDULE_NAME = 'test'; id cronid = System.schedule(SCHEDULE_NAME, '0 15 0-23 * * ?', new scheduledMaintenance()); System.abortJob(cronid);
And to schedule via the UI: Navigate to the Apex class list page - select "schedule apex"
let me know if this helps.
t
Gotcha. You might want to file a doc bug, then, as the docs state that abortJob() takes "String Job_name" rather than ID. The docs also say that System.schedule() returns a string, but the value of that string (the job ID) is never mentioned in the docs either (I just lucked into it).
Thanks!
j
On a related note, creating Apex Sharing Recalculations is still in pilot. As currently implemented in DE orgs, there's no way to specify the "scope" (batch size). It would be great if we could specify the scope and package that info too, especially for those of us that need to use Dynamic Apex to insert our Share objects, which can only be done with single-row-inserts per [ this other post ].
I created a doc bug a few weeks back. I will follow up with my doc writer to see what the status is.
Regarding the sharing recalc - why aren't you using the new batch interface? Perhaps I'm missing something obvious.
t
And the docs have been updated:
http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_scheduler.htm?SearchType=Stem
We are using the batch interface ... I'm talking about when I associate a Batchable class with an custom object for automatic sharing re-calc when a customer changes their org-wide sharing model. That UI (for the association of the Batchable class with the custom object, on the custom object page) does not have a place to enter the batch size parameter.
Once I've created that association via the UI, salesforce will automatically call "executeBatch(associatedClass)" for me, but with the default batch size, which might be too large for my purposes (eg, my batchable class might only work if invoked with a batch size of 50 or some such). Would be a non-issue except for the row-at-a-time SObject insert thing.
(thx for the doc update note - I'm working off a PDF from a month ago)
Sigh. Do you have a case# with this request. Seems a bit silly - we really should fix this.
The row-at-a-time limit on SObject DML is case 03474669.
I haven't opened a case about the recalc batch size UI.
It's now over 18 months later and query by Name is still not available. is there any status on this?
Also would like an update on Query by name.
As you all know, "name" is still not exposed in the CronTrigger table.
The only way to handle this is to store, permanently, the CronTrigger ID as returned by System.schedule:
So you can then delete it by ID.
If you, like us, have a bunch of these in the wild without having stored their ID (b/c it wasn't clear, at first, that System.schedule() returned the CronTrigger ID), then you (like us) will want to delete your old job & reschedule it so you can store the Job ID.
There are two things that can help you do this, even without a CronTrigger.Name field:
1. If you try to schedule a job w/ the same name, you will get an exception
2. Your CronExpression may be somewhat unique.
We actually have update code that leverages the above two facts to ensure we delete the old job (if it still exists) and then re-create it and store the Job ID that we get back.
The basic logic is this: Loop through all jobs whose CronExpression matches yours, delete the candidate job & try to reschedule your job. If you are able to reschedule, it means you deleted the right one. If not, you deleted the wrong one and need to rollback your changes.
There is a way to do this though it is undocumented and could be subject to breaking with new releases.
It is possible to add text after the year element of the Cron Expression - this text is ignored when the cron expression is parsed however it is available when querying the CronTrigger by CronExpression with a filter like "where CronExpression LIKE '% NAMEOFMYSCHEDULEDJOB'"
for(CronTrigger ct : [SELECT Id, CronJobDetail.Name, CronJobDetail.JobType
FROM CronTrigger
WHERE CronJobDetail.Name like 'Work Order%']){
// abort the job, try/catch because the job might not exist
// if it's being aborted manually or from another execution
try{
system.abortJob(ct.id);
} catch (exception e) {}
}
Worth noting that System.abortJob can only be used in the context of a User with the "Modify All Data" system permission, which means you can't have this cancellation via abort for ordinary users. Also note that you can't query the CronTrigger instances for a given name and then delete them either. So the following will always fail with a DML operation Delete not allowed error:
It seems really odd to me that an admin system permission is required to cancel jobs, even when they were submitted by the current User.More info on what caused this bug here: https://salesforce.stackexchange.com/questions/145545/scheduled-job-hanging-in-the-apex-jobs-queue/145757#145757?newreg=a05fb3eb1cdd4979b508f6b894ddf00c
Essentially jobs are getting scheduled in the past. Don't use a try/catch. Write an if check that adds a minute to the time if it is in the past.