1

My post-install script is failing on just one sandbox, and I can't figure out why. It has been working successfully for more than a year, on a number of different orgs, but this one fails. When it fails, I don't get any other details beyond the simple message "The post install script failed."

Here's my script:

public without sharing class ApiInstallHandler implements InstallHandler, UninstallHandler {

    public void onInstall(InstallContext context) {
        ApiSentinelRunLaterScheduled.scheduleSelf('');
    }

    public void onUninstall(UninstallContext context) {
        ApiSentinelRunLaterScheduled.cancelSelf('');
    }
}

And then, the dependent class:

// Sweeps up any sentinels that we couldn't start because they were
// triggered from a Batch or Future context. Time-based workflow
// would make more sense, but cannot be added to a managed package
public class ApiSentinelRunLaterScheduled implements Schedulable {

    private static String jobName = 'API Sentinel Run Later';

    public void execute(SchedulableContext SC) {
        NebulaApiWorker.runLaterWorkers();
    }

    public static void cancelSelf(String namePrefix) {
        List<CronTrigger> existingToCancel = [SELECT Id, CronJobDetail.Name, State 
                                              FROM CronTrigger 
                                              WHERE CronJobDetail.Name LIKE :namePrefix + jobName + '%'
                                              AND CronJobDetail.JobType = '7' 
                                              AND State != 'DELETED'];

        for(CronTrigger t : existingToCancel) {
            System.abortJob(t.Id);
        }


    }  

    public static void scheduleSelf(String namePrefix) {
        cancelSelf(namePrefix);

        ApiSentinelRunLaterScheduled asr = new ApiSentinelRunLaterScheduled();

        // every 15 minutes
        for(integer i=0; i < 4; i++) {
            String minutes = '' + (i*15);
            System.schedule(namePrefix + jobName + ' (' + minutes + ')', '0 ' + minutes + ' * * * ?', asr);
        }
    }        
}

Any ideas about how I can attack this? One obvious thing is to make a version of the package with a try..catch and then log the errors. But is there anything else to try before I go through that laborious process?

  • Code should work. The only difference between orgs (if it works for some and does not work for some) is the data, in your case - CronTrigger table. Try clearing it in the problematic org, also, try running this code manually on the org – Itai Shmida Aug 31 '17 at 4:37
  • Thanks, but I'd already checked the CronTrigger table, and I tried running the body of cancelSelf() in the dev console - neither has helper. I can't run the rest of it because the classes are not global, and I don't want to make them permanently global just for this. I think I'm going to have to add some logging and see if that helps :( – Aidan Aug 31 '17 at 8:19
  • Logging is always good. But can't you run the rest of the code from executeAnonimous? – Itai Shmida Aug 31 '17 at 8:21
  • It's not global, so nope, can't run it. – Aidan Aug 31 '17 at 8:22
  • I mean just run this: // every 15 minutes for(integer i=0; i < 4; i++) { String minutes = '' + (i*15); System.schedule(namePrefix + jobName + ' (' + minutes + ')', '0 ' + minutes + ' * * * ?', asr); } from Execute Anonimous in dev console – Itai Shmida Aug 31 '17 at 8:24
0

I've logged the error during the post-install and it is:

The Apex job named "API Sentinel Run Later (0)" is already scheduled for execution. Class.Nebula_Api.ApiSentinelRunLaterScheduled.scheduleSelf: line 34, column 1 Class.Nebula_Api.NebulaApiInstallHandler.onInstall: line 5, column 1

So, I ran this in the dev console:

List<CronTrigger> triggers = [SELECT Id, CronJobDetail.Name, State FROM Crontrigger ALL ROWS];

for(CronTrigger ct : triggers) {
    System.debug(ct.CronJobDetail.Name + ': ' + ct);
}

Which gives the following debug output (just one row):

09:46:39:009 USER_DEBUG [4]|DEBUG|pi_Async_Request_Scheduler-1503878362374: CronTrigger:{Id=08e4E0000074VEvQAM, CronJobDetailId=08a4E0000074W5VQAU, State=WAITING}

Which seems to mean that there's a phantom instance of the scheduled job already recorded in the sandbox. I can't find it, so I can't cancel it. Which looks like an interaction between two known issues:

  1. AsyncApexJob row for Scheudled Apex Jobs is not sandbox copied https://success.salesforce.com/issues_view?id=a1p300000008Ym6AAE
  2. Scheduled batch "already scheduled"

So, the solution is to throw the current time in ms on to the end of the scheduled job name. Interestingly, if you look at the debug output from what I tried above, you can see that Pardot are doing this for their scheduled job!

  • How did you manage to log the error and see those logs? – zaitsman Sep 11 at 0:18

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.