8

I've got a Batch Apex Class like so.

(It happens to use the Dan Appleman decoupler pattern, augmented for batch. Thanks Dan!)

public with sharing class Dispatcher implements Database.Batchable<SObject> {

    Database.Batchable<SObject> batch =
    (Database.Batchable<SObject>)Type.forName('Implementation').newInstance();

    public Database.QueryLocator start(Database.BatchableContext context) {
        return (Database.QueryLocator)this.batch.start(context);
    }

    public void execute(Database.BatchableContext context, List<SObject> scopes) {
        this.batch.execute(context, scopes);
    }

    public void finish(Database.BatchableContext context) {
        this.batch.finish(context);
    }

}

When I go to delete the class through the Salesforce UI it chokes like so:

Unable to Complete the Requested Change

Your changes could not be completed for the following reasons:

apex-job-dependencies

Or if I try to delete the class through the Metadata API it fails similarly:

All Component Failures:

1 classes/Dispatcher.cls -- Error: This apex class is referenced elsewhere in salesforce.com. Remove the usage and try again. : Apex Job - 707j0000005AGlD.

This apex class is referenced elsewhere in salesforce.com. Remove the usage and try again. : Apex Job - 707j00000059kad.

This apex class is referenced elsewhere in salesforce.com. Remove the usage and try again. : Apex Job - 707j00000059ek2.

This apex class is referenced elsewhere in salesforce.com. Remove the usage and try again. : Apex Job - 707j0000005AXyO.

This apex class is referenced elsewhere in salesforce.com. Remove the usage and try again. : Apex Job - 707j0000005AjxE.

This apex class is referenced elsewhere in salesforce.com. Remove the usage and try again. : Apex Job - 707j0000005ARmn.

This apex class is...

If I query any one of those AsyncApexJobs they look like this:

AsyncApexJob:{
    JobType=BatchApex,
    Status=Completed,
    NumberOfErrors=101,
    ExtendedStatus=First error: Attempt to de-reference a null object,
    CreatedById=005j0000000X37nAAC,
    CreatedDate=2014-12-23 13:34:56,
    Id=707j0000005AzdiAAC,
    JobItemsProcessed=100,
    TotalJobItems=100,
    CompletedDate=2014-12-23 13:35:37,
    ApexClassId=01pj0000001bltZAAQ
}

My question: if those are Completed jobs, why do they block deletion of the class?

  • 1
    I'd expect that any completed jobs would have called the public void finish(Database.BatchableContext context) method which presumably would have closed the references depending on your implementation. – crmprogdev Dec 27 '14 at 19:57
  • Thanks for noodling it @crmprogdev. I wonder if the decoupler pattern is straightforward on Schedulable interface, but perhaps there are some leaky side effects happening as applied to Database.Batchable like this. – bigassforce Dec 27 '14 at 20:03
  • Let just say this from my experience in working with Appleman's Trigger code. He's admitted that the code he publishes in his books is example code used to illustrate the concepts and is not intended to be out of the box "working" code. So if what you've taken is from his 2nd edition (I have 1st Ed), I wouldn't expect it to fully function without needing additional finessing. There are some missing "leaps" not covered in the book that need to be handled in your code he doesn't address. – crmprogdev Dec 27 '14 at 20:08
5

Can you try invoking the apex method System.purgeOldAsyncJobs from anonymous apex? This will clear out the old AsyncApexJob records that are blocking the deletion. I have a vague memory of it solving this issue for me in the past, and seems easier than aborting completed jobs!

Logically I see what salesforce is getting at here, deleting your class would leave these job entries as orphaned without an apex class associated, which is potentially quite problematic from a logging and auditing perspective. By clearing these listings there's then no referential integrity problem.

If you want to purge all AsyncApexJob listings pass Date.today() to purgeOldAsyncJobs.

| improve this answer | |
  • Very sage advice, will give this a go as soon as I can replicate! FWIW it hasn't historically been a problem to delete classes with related AsyncApexJob history... only ever happening from time to time. – bigassforce Dec 27 '14 at 21:17
5

I found a way to permit the deletion of the class. But it seems a bit counter-intuitive:

  1. visit /setup/own/deleteredirect.jsp?setupid=ApexClasses&delID={clsid}

  2. from the table of apparent dependencies, copy the IDs from each URL into code like so:

    System.abortJob('707j0000005AGlD');
    System.abortJob('707j00000059kad');
    System.abortJob('707j00000059ek2');
    System.abortJob('707j0000005AXyO');
    System.abortJob('707j0000005AjxE');
    System.abortJob('707j0000005ARmn');
    System.abortJob('707j0000005A6Ej');
    System.abortJob('707j00000059XS3');
    System.abortJob('707j00000059y6Y');
    System.abortJob('707j0000005Aw43');
    System.abortJob('707j0000005AMR4');
    System.abortJob('707j00000059vX5');
    System.abortJob('707j0000005Ay1x');
    System.abortJob('707j00000059XWB');
    System.abortJob('707j0000005Azdi');
    
  3. run the above Execute Anonymous from the Developer Console

  4. re-attempt the deletion (which should now succeed)

Querying the same ID results in something like this:

AsyncApexJob:{
    JobType=BatchApex,
    Status=Aborted,
    NumberOfErrors=101,
    ExtendedStatus=First error: Attempt to de-reference a null object,
    CreatedById=005j0000000X37nAAC,
    CreatedDate=2014-12-23 06:00:06,
    Id=707j0000005AGlDAAW,
    JobItemsProcessed=100,
    TotalJobItems=100,
    CompletedDate=2014-12-27 19:47:45,
    ApexClassId=01pj0000001bltZAAQ
}

So ultimately it's a way to get the delete to work but I've lost confidence in the dependency effects of Completed jobs, and had no idea they could go from Completed to Aborted status!

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.