0

I wanted to double check on my scheduler to make sure is was compiled correctly. I need it to run every minute, which is not possible, so I have it scheduled for every 15 minutes. Testing is difficult because I have to wait 15 minutes every time I want to test one change. Is there a way around this?

While I am waiting for the newest change I wanted to check with you guys to see if everything looked okay. I am getting failed Status Details but because the limit is 255 characters, I am unable to see the entire failure string. So I am trying to troubleshoot (slowly...every 15 minutes. sadface). Also, why is it skipping scheduled job 1?

Apex:

global class AutoStartSchedulerUpdateStageName {
   global void AutoStartSchedulerUpdateStageName() {}

   public static void start()
   {
       System.schedule('Scheduled Job 1', '0 0 * * * ?', new AutoStartScheduler());
       System.schedule('Scheduled Job 2', '0 15 * * * ?', new AutoStartScheduler());
       System.schedule('Scheduled Job 3', '0 30 * * * ?', new AutoStartScheduler());
       System.schedule('Scheduled Job 4', '0 45 * * * ?', new AutoStartScheduler());
   }
}

global class AutoStartScheduler implements Schedulable {

    global void execute(SchedulableContext SC) {
        AutoStartSchedulerLogic a = new AutoStartSchedulerLogic();
    }
}

global with sharing class AutoStartSchedulerLogic {
    global AutoStartSchedulerLogic(){
        List<Opportunity> brokerAPIOppty = [SELECT Id FROM Opportunity WHERE CreatedBy.Name = 'nfapi Site Guest User' AND StageName = 'Identified' AND RecordType.Name = 'Broker WC Oppty'];
        if(!brokerAPIOppty.isEmpty()){
            for(Opportunity o : brokerAPIOppty) {
                o.StageName = 'Statements In - MCA';
            }
            update brokerAPIOppty;
        }
    }
}

enter image description here

enter image description here

UPDATE: Triggers and Callouts dislike each other so a future method is needed. Future methods can't return values back into the flow because of sync/async issues. All other workarounds (ie: updating a field in sf with the webservice values etc..) caused order of execution issues/"uncommitted work pending".

The ideal flow we need is:

  1. Third Party Insert
  2. REST service calls apex class
  3. apex updates Opportunity field
  4. Opportunity Trigger fires
  5. class is called
    • this class calls the flow and passes input parameters
  6. flow is called
  7. flow wait element is called
  8. flow calls an apex class that:
    • webservice is called in this class
    • platform events are created in this class
  9. flow resumes when platform event is published
  10. continues logic...

Two callouts are creating the loop error.

3

Your first job is set to run on the zero minute of the hour, which is exactly what your screenshot shows it doing. If you schedule it when you're already past the zero minute, Salesforce does not run it immediately. (That behavior is not analogous to time-based workflow rules).

As far as testing goes, you absolutely can test scheduled jobs in an Apex unit test by scheduling the job between Test.startTest() and Test.stopTest(). This will force the job to run synchronously.

Additionally, since you've wisely broken your logic out into a handler class, you can unit test the handler class separately to determine why you're getting errors. Unit testing will also generate logs you can inspect to view error details.

A couple notes on code style:

  • You don't need to check whether the list is empty before iterating over it. (It will not be null).
  • It's generally considered unwise to perform DML in a class initializer. I'd suggest making the method that performs work in your handler class a static method, since it does not need to maintain state.
  • You're mixing global and public access modifiers. These classes should be public unless you have a specific reason they need to be global.

Lastly, and most importantly: why is this a scheduled class rather than a trigger or workflow rule?

| improve this answer | |
  • Thank you, all great feedback. To answer your last question, we have a third party API that has their own SF login. They insert Leads directly into our SF which fires off a series of logic that eventually fires off a trigger, that fires off a webservice. All of this together causes a number of issues with callout loops not allowed (salesforce.stackexchange.com/questions/6142/…) and calling webservices from triggers (future methods needed). – Olivia Feb 19 '18 at 23:00
  • The process should be: Third Party Inserts Lead --> Flow Fires --> Scheduler Logic --> Calls Apex Class/ Updates Opportunity --> Opportunity Trigger Fires --> Webservice is called --> Values are returned back to flow --> Logic continues... – Olivia Feb 19 '18 at 23:01
  • That's definitely a complex architecture, but I don't see how it prohibits a tiny before insert (and/or before update) trigger on Opportunity, which does not fire any additional DML. – David Reed Feb 19 '18 at 23:03
  • too long of a response to type in a comment, I will update the post – Olivia Feb 20 '18 at 17:43
  • 1
    I appreciate your feedback on the initial question. I know this got a little off topic so I apologize for bringing in all of the extra complexities. As of now, this is super helpful, I will be able to debug synchronously! – Olivia Feb 20 '18 at 19:11
2

Too long for a comment.

  1. Don't use the global access modifier unless you need it!
    • You almost never and definitely not for Schedulable implementations, let alone classes they call further down the chain.
  2. You haven't included any logic which cannot be implemented just as well or better in a trigger.
    • If you are using a Schedulable implementation to escalate privileges, consider using Platform Events instead.
  3. You can just test your service level logic directly without waiting for the schedule to run. Just go to Execute Anonymous and run the same logic you have in your execute block.
    • Testing via anonymous scripts has the added advantage of being able to wrap the logic in a try/catch block.
    • It will be easier to catch debug logs for a transaction you actively initiate.
  4. Checking if the list is empty doesn't add any value.
  5. Don't use stateful methods when you have no state.
    • Mark your AutoStartSchedulerLogic method as static
    • Give it a return type (e.g. void) so it is no longer a constructor.
    • Try coming up with a more informative name, like promoteStage or some such.
| improve this answer | |
  • I updated the post with why we can't use a trigger instead of a scheduler. Where would you suggest I use a trigger? The incoming third party and the webservice callout is counting as two rest services which is creating the Callout loop not allowed error. I believe I have to split the transactions apart so there is no "loop" – Olivia Feb 20 '18 at 17:54
  • @Olivia Perhaps try laying out your goals at a higher level. It's not really clear why you want to implement Flow, Platform Events, webservice, or any of the technology stack you mention above. If your stack is this complex, you probably should be paying someone to assist. Free help is likely not going to cut it, and the format here is to constrained for the breadth of conversation you need to carry out. – Adrian Larson Feb 20 '18 at 18:15
  • I appreciate your feedback on the initial question, I know this thread got a little overly complex. We can't use a trigger for a number of reasons that are too much to lay out in this thread. I wasn't in need of architecture help, so your feedback on the scheduler code was great. Thank you! – Olivia Feb 20 '18 at 19:14

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.