Easily Abort Async Apex Jobs by Class Name
The Problem
In cleaning up some code in a sandbox, I needed to delete a class that implements the Queueable interface, and the jobs for it didn't appear to be visible in the Salesforce UI. I'm aware of how to deal with such jobs, but I was curious to know if any easier ways to do so had been added to the platform over the years. What I discovered was that no, there haven't, but worse the Salesforce Documentation for cancelling such a job doesn't really go out of the way make it easy to use. For example, it starts with this:
To abort long running batch, future or scheduled Apex jobs, you may use System.abortJob() from the Developer Console (execute anonymous window) and pass the job id to this method. Ie., system.abortJob('7078000000XXXXX')
Which isn't exactly helpful if you don't have the Id of the job, though they do go on to suggest you can find that using the following query:
SELECT ApexClassId,CompletedDate,CreatedById,CreatedDate,ExtendedStatus,Id,JobItemsProcessed,JobType,LastProcessed,LastProcessedOffset,MethodName,NumberOfErrors,ParentJobId,Status,TotalJobItems FROM AsyncApexJob where status = 'queued'
Which is sort of useful, but then they're not really telling you how to identify the particular job you want, and there could well be tens of them if not more.
A Simpler Approach
First of all, this query contains a lots of fields not required here, and rather than fetching the Apex Class Id (because we all know those off by heart, right?) we can get the class name:
SELECT Id, ApexClass.Name from AsyncApexJob where Status = 'Queued'
That will give you all the job Ids, but again, why do it in two steps, querying in the dev console and then using Anonymous Apex to do the delete? As long as you're confident in what you want to delete, it doesn't take much to turn this into a short piece of Anonymous Apex that does all the work for us:
for(AsyncApexJob job : [select Id from AsyncApexJob where ApexClass.Name = 'YourClassHere' and Status = 'Queued'])
{
System.abortJob(job.Id);
}
Job done. I'm somewhat confused as to why the documentation doesn't go into the detail of how to do this using human readable values, like the name of the class in question.