0

I haver a scheduled job that runs every fifteen minutes. It runs fine for several months and then randomly it will stop running and doesn't reschedule for the next run. The apex jobs showed an "attempt to de-reference a null object error, but didn't give me a line number.

Here is the code I'm running:

global class OrderApprovalDeadlineScheduler implements Schedulable {

  Boolean cacheLoaded = false;

  private BusinessHours getDefaultBusinessHours() {
    BusinessHours bh = new BusinessHours();
    if(cacheLoaded) return bh;
    bh = [SELECT Id FROM BusinessHours WHERE IsDefault=true];
    cacheLoaded = true;
    return bh;
  }

    global static String scheduleIt() {
        datetime nextScheduleTime = system.now().addMinutes(15);
        integer minute = nextScheduleTime.minute();
        integer second = nextScheduleTime.second ();
        integer hour = nextScheduleTime.hour();
        integer year = nextScheduleTime.year(); 
        integer month = nextScheduleTime.month(); 
        integer day = nextScheduleTime.day();
        string cronvalue = second + ' ' + minute + ' ' + hour + ' ' + day + ' ' + month + ' ? ' + year;
        string jobName = 'Self Rescheduling Order Approval Deadline Scheduler ' + nextScheduleTime.format('hh:mm');

        OrderApprovalDeadlineScheduler scheduler = new OrderApprovalDeadlineScheduler();
        return system.schedule(jobName, cronvalue, scheduler);
    }

  global void execute(SchedulableContext sc) {
    BusinessHours bh = getDefaultBusinessHours();
    Map<Id, Order_Approvals__c> recordsToUpdate = new Map<Id, Order_Approvals__c>();
    for(Order_Approvals__c oa : [select Approval_Deadline__c, Approval_Deadlines_Missed__c from Order_Approvals__c where Response__c = NULL]) {
      if(system.now() >= oa.Approval_Deadline__c) {  
        oa.Approval_Deadline__c = BusinessHours.add(bh.Id, oa.Approval_Deadline__c, 32400000);
        oa.Approval_Deadlines_Missed__c = oa.Approval_Deadlines_Missed__c + 1;
        recordsToUpdate.put(oa.Id, oa);
      }
    }
    if(!recordsToUpdate.isEmpty() && recordsToUpdate.size() > 0) {
        List<Database.Saveresult> results = Database.update(recordsToUpdate.values(), false);
        for(Database.SaveResult sr : results) {
            if(!sr.isSuccess()) {
                for(Database.Error err : sr.getErrors()) {
                    // process any errors here 
                    system.debug(err.getMessage());
                    system.debug(err.getStatusCode());
                }                   
            }
        }
    }
    try { 
        system.abortJob(sc.getTriggerId()); 
    } 
    catch (exception e) {
        system.debug('************ schedule job exception while aborting: ' + e);
    }
    system.debug('************* schedule job executing'); 
    scheduleIt();
  }

}

As I was looking over the code, I was looking for where the null error might be occurring. I could add a null check before referencing the Approval_Deadline__c field in the code right after the loop starts. Is there a way to capture the error when it occurs and email me with the error and line number so I can fix the issue. It has been hard to track down since it happens only randomly. Normally about every 6 months or so, the job will fail and not reschedule and I have to go back and run the ScheduleIt() method in the anonymous window to get the job running again.

1 Answer 1

2

I think these lines are clearly your candidates for NullPointerException:

  if(system.now() >= oa.Approval_Deadline__c) {  
    oa.Approval_Deadline__c = BusinessHours.add(bh.Id, oa.Approval_Deadline__c, 32400000);
    oa.Approval_Deadlines_Missed__c = oa.Approval_Deadlines_Missed__c + 1;

If oa.Approval_Deadline__c or oa.Approval_Deadlines_Missed__c is null, there's your exception, and this will stop execution from reaching your rescheduling code.

I generally don't like to capture NullPointerException and handle it because it is such an easy error to avoid in the first place. While you can add a try/catch block here, trap the exception, and send an email, I would recommend instead that you simply write logic to handle the cases where those fields are empty.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .