Relax — your batch scheduling woes are over

**Quick check to make sure this post is worth 5 minutes of your precious work day:**

If you have ever wanted:

(1) To run long chains of Batch Apex jobs in sequence without using up scheduled Apex jobs
(2) To run batch/scheduled Apex as often as every 5 minutes every day
(3) To manage, mass-edit, mass abort, and mass-activate all your scheduled and aggregable/chained Apex jobs in one place, in DATA
(4) To avoid the pain of unscheduling and rescheduling Apex jobs when deploying

Then keep reading 🙂

A recent (well, maybe not so recent — is it June already???) blog post by Matt Lacey really struck a chord with me. Matt highlights one of the biggest developer woes related to using Scheduled Apex — whenever you want to deploy code that is in some way referenced by an Apex Class (or classes) that is/are scheduled, you have to unschedule all of these classes. With Spring 12, Salesforce upped the limit on the number of Scheduled Apex Classes from 10 to 25 (ha–lellujah! ha–lellujah!). However, with 15 more scheduled jobs to work with, this have-to-unschedule-before-deploying problem becomes even more of a pain.

But this isn’t the only woe developers have related to asynchronous Apex. An issue that has shown up a lot lately on the Force.com  Developer Boards and LinkedIn Groups is that of running Batch Apex jobs in sequence — run one batch job, then run another immediately afterwards. Cory Cowgill published an excellent solution for accomplishing this, and this has been the go-to method for linking Batch Apex jobs ever since. But one of the problems with his method is that it leaves a trail of scheduled jobs lying in its wake — seriously cluttering your CronTrigger table. If you want to run these batch process sequences often — e.g. kicking them off from a trigger, or running them every day (or even every hour!), you have to start “managing” your scheduled jobs more effectively.

A third issue often cited by developers is the frequency at which jobs can be run. Through the UI, a single CronTrigger can only be scheduled to run once a day. Through code, you can get down to once an hour. If you wanted to, say, run a process once every 15 minutes, you’d have to schedule the same class 4 times — using up 4/25 (16%) of your allotted scheduled jobs — and you have to manage this through Apex, not the UI.

As I mulled over these issues, I thought, there’s got to be a better way.

There is.

Enter Relax

Relax is a lightweight app I’m about to release, but before I do, I’m throwing it out for y’all to try as a public beta. (The install link is at the end of the post, but restrain yourself, we’ll get there 🙂 )

Broadly speaking, Relax seeks to address all of these challenges, and a whole lot more.

At a high level, here are a few of the things it lets you do:

  1. Manage all your individually-scheduled Apex jobs in data records (through a Job__c object). Jobs can be mass scheduled and mass aborted, or mass exported between orgs, and then relaunched with clicks, not code.
  2.  Create and schedule ordered Batch Apex “chains” of virtually unlimited length, with each “link” in the chain kicking off the next link as soon as it finishes. And all of your chained processes are handled by, on average, ONE Scheduled Job.
  3. Schedule jobs to be run as often as EVERY 1 MINUTE. ONE. UNO.
  4. Run ad-hoc “one-off” scheduled jobs without cutting into your 25
Let’s jump in.
 
Individual vs. Aggregable
In Relax, there are 2 types of jobs: individual and aggregable. You create a separate Job__c record corresponding to each of your Individual jobs, and all of the detail about each job is stored in its record. You can then separately or mass activate / deactivate your jobs simply by flipping the Active? checkbox. Each Individual job is separately scheduled — meaning there’s a one-to-one mapping between a CronTrigger record and an Individual Job__c record. Here’s what it looks like to create an Individual Job. You simply specify the CRON schedule defining when the job should run, and choose a class to run from a drop-down of Schedulable Apex Classes.

Aggregable jobs, on the other hand, are all run as needed by the Relax Job Scheduler at arbitrary increments. For instance, you could have an aggregable job that runs once every 5 minutes that checks for new Cases created by users of your public Force.com Site, whose Site Guest User Profile does not have access to Chatter, and inserts Chatter Posts on appropriate records. You could have a job that swaps the SLA of Gold/Bronze SLA Accounts once every minute (contrived, yes, but OH so useful 🙂 Or you could have a series of 5 complex batch apex de-duplication routines that need to be run one after the other, set them all up as separate aggregable jobs, assign orders to them, and have the entire series run once every 15 minutes, every day. Here’s what the SLA swapper example looks like:

How do I use it?
 What do you have to do for your code to fit into the Relax framework? It’s extremely simple. For Individual Jobs, your Apex Class just needs to be Schedulable. For Aggregable Jobs, there are several options, depending on what kind of code you’d like to run. For most devs, this will be Batch Apex, so the most useful option at your disposal is to take any existing Batch Apex class you have and have it extend the “BatchableProcessStep” class that comes with Relax:

// relax's BatchableProcessStep implements Database.Batchable<sObject>,
// so all you have to do is override the start,execute,and finish methods
global class SwapSLAs extends relax.BatchableProcessStep {

	// Swaps the SLA's of our Gold and Bronze accounts

        // Note the override
	global override Database.Querylocator start(Database.BatchableContext btx) {
		return Database.getQueryLocator([
                     select SLA__c from Account where SLA__c in ('Gold','Bronze')
                ]);
	}

	global override void execute(Database.BatchableContext btx, List<SObject> scope) {
		List<Account> accs = (List<Account>) scope;
		for (Account a : accs) {
			if (a.SLA__c == 'Gold') a.SLA__c = 'Bronze';
			else if (a.SLA__c == 'Bronze') a.SLA__c = 'Gold';
		}
		update accs;
	}

        // The ProcessStep interface includes a complete() method
        // which you should call at the end of your finish() method
        // to allow relax to continue chains of Aggregable Jobs
	global override void finish(Database.BatchableContext btx) {
		// Complete this ProcessStep
		complete();
	}

}

That’s it! As long as you call the complete() method at the end of your finish() method, relax will be able to keep infinitely-long chains of Batch Jobs going. Plus, this framework is merely an extension to Database.batchable — meaning you can still call Database.executeBatch() on your aggregable Batch Apex and use it outside of the context of Relax.

Relax in action

In our org, we have 4 jobs set up: 1 individual, 3 aggregable. To kick them off, we select all of them, and change their Active? field to true. Here’s what it looks like after we’ve mass-activated them:

And here’s what the Scheduled Jobs table (accessible through the Setup menu) looks like. Since Case Escalator was set to be run individually, it has its own job. Then there’s a single “Relax Job Scheduler”, which runs every 5 minutes (I’ll probably drop this down to every 1 minute once I officially release the app), checking to see if there are any aggregable Jobs that need to be run, and running them:

Every time Relax Job Scheduler runs, the very first thing it does is schedules itself to run again — regardless of what happens during any processing that it initiates. It queries the “Next Run” field on each Active, Aggregable Job__c record that’s not already currently being run, and if Next Run is less than now, it queues it up to be run as part of a Relax “Process”. Each Process can have an arbitrary number of ProcessSteps, which will be executed sequentially until none remain. If both the current and next ProcessSteps are BatchableProcessSteps, Relax uses a “Process Balloon” to keep the Process “afloat” — essentially launching a temporary scheduled job that is immediately thrown away as soon as the next ProcessStep is begun.

One-off Jobs

Another powerful feature of Relax is the ability to effortlessly launch one-off, one-time scheduled jobs, without having to worry about cluttering the CronTrigger table with another scheduled job. It takes just 1 line of code, AND you can specify the name of the class to run dynamically — e.g. as a String! Reflection ROCKS!!!

// Schedule your job to be run ASAP,
// but maintain the Job__c record so that we can review it later
relax.JobScheduler.CreateOneTimeJob('myNamespace.AccountCleansing');

// Schedule your job to be run 3 minutes from now,
// and delete the Job__c record after it's run
relax.JobScheduler.CreateOneTimeJob(
    'SwapSLAs',
    Datetime.now().addMinutes(3),
    true
);

Try it out for yourself!

Does this sound awesome to you? Give it a test run! Install the app right now into any org you’d like! Version 1.1 (managed-released)

Please send me any feedback you may have! What would make this more usable for you? I’ll probably be releasing the app within the next month or so, so stay tuned!

49 thoughts on “Relax — your batch scheduling woes are over

  1. Awesome solution to a very painful problem. The inability in the default UI to “inactive” scheduled jobs for deployments is such a major painpoint that alone is a great feature. To further extend it to enable folks to link batch jobs is icing on the cake. Very cool!

  2. Very promising…though I did try and and got the error “Unable to create an instance of extension ‘JobEditController’ ” when adding a new ‘Job’…i haven’t created any code as yet…just fiddling for now ?

    1. Phill, thanks for you feedback! For the app to be useful, you’ll have to create at least one sample schedulable or aggregable Batch Apex class, such as my “SwapSLAs” class, and then create a job tied to it. If you don’t have any such classes created, the app won’t be very useful — I am definitely interested in the “JobEditController” error, though. Did “JobEditController” show up as one of the available “Aggregable Classes” or “Schedulable Classes”?

      1. Zach, I installed in my dev org, went straight to All tabs->Jobs, hit new and then…

        Visualforce Error

        Unable to create an instance of extension ‘JobEditController’

        Figured i’d done something dumb – would love to see this working

  3. Do you realistically see jobs starting every five minutes? My experience is that scheduled jobs run between 0 and 10 minutes after the time they’re theoretically ininitiated.

    1. Jeremy, that’s a good point. It really depends on the magnitude of the batch process involved. In my experience, small Batch Apex jobs (e.g. ones whose QueryLocators only return < 10000 records) run almost instantly. But large jobs — e.g. ones that involve 1,000,000 records — often linger in the "Preparing" stage for several minutes before kicking off, and then, of course, the actual execution might take a good 10 minutes. But, of course, these are the sorts of jobs that you don't usually run every 5 minutes — more like every 5 days. But for small jobs, execution is almost instant, and there are lots of scenarios (e.g. sending out reminder emails prior to an event) where having the ability to run a process every 5 minutes is critical. And when there's only a few records to process (e.g. just those reminders whose "Send Time" is in the last 5-10 minutes), the batch apex jobs will be small, so they'll get run almost instantly.

  4. Relax lovers! I have finally gotten around to open-sourcing Relax — check out the GitHub repo: https://github.com/zachelrath/Skoodat-Relax

    I won’t be releasing it as a full Managed – Released version until Winter 13, which will bring the ability to execute Batch Jobs sequentially without having to do what Relax currently does: creating ‘temporary’ scheduled Apex Jobs and then destroying them right before starting the next Batch job in line.

    I’ll try to move my example classes (e.g. BatchAccountsUpdater.cls, CaseEscalator.cls, SwapSLAs.cls) into an ‘examples’ directory.

    I’m also (potentially) doing an Unconference Session on Relax at 1 PM tomorrow in DevZone — stop by and we can discuss Batch/Scheduled job hassles and how Relax can help resolve them!

    1. Zach,
      Thank you for sharing your efforts on Relax with the community. The timing is perfect for me on my current project; I have been wondering about the release schedule, hoping I might be able to make use of it. This will be a big help to me, and a great benefit to many others out there.

      When I started looking at the code, I got to the 4th line in the trigger and had to stop and come here to post. That ternary as a for loop iterator is SLICK!

      1. Thanks Jeff. I am hoping to put up a Managed Released package and put it up on the appexchange soon (so that users don’t have to add this code to their existing code bases, and so that they’ll get all the advantages of the code being part of an AppExchange app (e.g. separate execution context, governor limits, etc.), so please fork and submit a pull request if you have any changes!

  5. Hi Zach,

    Amazing tool!, just what i was looking for.
    Unfortunately installation failed for me.

    “Error Message: The post install script failed.”

    Any idea?

    Thanks

    1. The post-install script right now is just spitting out some debug information. I’ve been meaning to put out a new version without it, just haven’t gotten around to it yet. Will let you know when I do. Usually the script succeeds for people, strange that it did not.

      Zach

  6. Zach, I have a question about the whole scheduling with Aggregable Batch Proceses. I set the increment for your two sample batch jobs to run every 10 minutes. But in reality they run every 15 minutes (From looking in the Apex Logs). Can you explain this?

    1. Hi Bryan, good question. There are several things that may delay the actual execution time of your processes.

      First, long-running batch processes can take several minutes, sometimes even longer, to finish running, and so each subsequent job in the process chain will not start until its preceding job has finished. This is necessary in order to have all jobs handled by a single Scheduled Apex job. In a future release (feel free to code it yourself and submit a pull request on Github!) I’d like users to have the option of having certain jobs run in parallel — e.g. giving users to have one sequence of jobs executing in a separate, dedicated Scheduled Apex job execution context.

      Second (and more likely the cause of the delay in this scenario) the actual scheduled Apex runtime currently only runs once every 5 minutes to check for jobs that need to be run. This was only done as a precaution while prototyping, and I think it can be safely removed — should be done in a future release.

      Zach

      1. Ahh I figured as much thank you. So in the current situation I have right now, I want to schedule 8 Aggregable jobs in order to run once a day at a certain time (Lets say 2:00 A.M.) How exactly would I accomplish this in the scheduling Visualforce page? Would I just create all the aggregable jobs to run once a day and set the next run time to whatever I wanted it to be?

      2. Exactly, set all the Aggregable jobs to run once daily, and set the next run time to be 2 AM on the first day (e.g. tomorrow) that you’d like the process to run. If the order of execution matters, set the Order field on each Aggregable job so that lower-numbered jobs will happen before higher-numbered jobs.

      3. Perfect, I am going to try setting that line 116 to 1 minute and see what happens. Also when you do release to the AppExchange, I will be giving it 5 stars and an excellent review. This is really really nice.

  7. Zach, I installed Skoodat Relax in my DE. Now, all I need to do is schedule my individual job to run every minute. I have created the Apex class that implements schedulable with execute method that does the required operations. Now, how do I schedule this to run every minute? I go to Jobs tab and try to schedule it, but I see no apex classes in the “Aggregable Apex Class” picklist. None of the relax example classes show up here as well. Now, if I go to the default Salesforce Scheduler, it shows my class as well as the relax example classes. Is there any step I’m missing?

    1. Madhu, in order for your class to run every minute, it will need to be an Aggregable Class (it can be a Schedulable class as well, but classes that are just Schedulable cannot be run every minute). To make it an Aggregable class, the easiest thing to do would be to have your Apex class extend the “relax.BatchableProcessStep”, as in the “SwapSLAs” example (this class is available on the GitHub page). This will reformatting your code into Batch Apex form, but you can essentially just have a dummy start method that does a query that will only return one row, e.g. a query on the User account with limit 1. THen in the execute method you can run your logic. That’s the easiest way to do it right now.

      However your question suggests the need for a “SchedulableProcessStep” class. I have added this as an enhancement: Add SchedulableProcessStep to allow easy incorporation of Schedulable jobs into Relax processes

  8. Zach, Thanks for your response. I did what you suggested and ceated my class ProcessResultsQueueBatch that implements relax.BatchableProcessStep. When I try to create the job, the class shows up now in the picklist. But when I try to save, it errors out with Error: ‘ProcessResultsQueueBatch’ is not a valid Apex Class. It is a valid apex class, so not sure why it says that. Is there any that it is looking for? Also when I select “run individually” my other class that implements schedulable shows up fine. Can I set the cron schedule to run every minute? Even when I use run individually option, I see the same error when try to save. However, if I use your example classes, it saves fine.

    1. Sathya,

      No, you don’t have to manually schedule/unschedule it — all you have to do is mark your Job__c records as Active/Inactive, and Relax will automatically schedule/unschedule its one “Job Scheduler” job, and any Individually Scheduled jobs, as needed. Salesforce shouldn’t make you unschedule Relax’s Scheduled Job when you’re doing unrelated deployments — unless the code that you are pushing references Relax’s Job Scheduler code or the code for any Individually Scheduled jobs.

      Zach

  9. You say:

    A third issue often cited by developers is the frequency at which jobs can be run. Through the UI, a single CronTrigger can only be scheduled to run once a day. Through code, you can get down to once an hour. If you wanted to, say, run a process once every 15 minutes, you’d have to schedule the same class 4 times — using up 4/25 (16%) of your allotted scheduled jobs — and you have to manage this through Apex, not the UI.

    But why can’t you set a cron expression for the job as 0 0/15 0 * * ?

    Wouldn’t that run every 15 minutes and only be one job?

    1. No, that is not possible from within Apex — try it, and you’ll see that Apex only supports integers 0-59 for the second and minute parts of the CRON expression. So you’d get an error if you tried to use a schedule an Apex job by using a CRON expression that contained any special characters, such as “/”, within the second or minute “0 0/15 …. ” portions. See the docs: http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_scheduler.htm

  10. Hi Zach,
    Thanks for an excellent insight about this app.I have successfully installed in my developer edition but i am getting a TImeLimit exceeded issue when i am clicking on the New Job 😦 . I am not sure if everybody is facing the same issue or its particular to me. Any help in this regards will be greatly appreciated.

    Sai

    1. Hello Sai,

      Thanks for your feedback! I am guessing that the reason you’re getting “TimeLimit exceeded” is that you have a lot of ApexClasses in your org. The current version of Relax loops over all ApexClasses in your org and tries to determine if they implement relax.BatchableProcessStep, if you are doing an AggregableJob, or Schedulable, if you are doing an Individual Job. I am considering making the ApexClass picker an AutoComplete instead of a dropdown, which would eliminate this problem.

      Regards,

      Zach

      1. Hi Zach,
        Thanks for the quick reply. Do we have a limit on the number of classes the code can scan?If so what was the limit as i have around 350 classes in my production org. I have tested this in my developer edition where the number of classes were lessthan 20. Do you anticipate this issue to be fixed in next release Zach, if so do you have any time limit.Thanks in Advance zach.

      2. Sai,

        I have just released Beta 5, which has the changes I described. Since this is a Beta package still, you’ll have to Uninstall and install the new version. This version incorporates an Autocomplete search on Apex Classes instead of a Picklist, so this avoid any issues related to the number of classes in an org. Let me know if this resolves the issue.

        Regards,

        Zach

      3. Thanks Zach.I think the old issue is fixed and i am able to create a new Job record. I will be deploying in my sandbox environment and test the same.Thanks once again for the timely help and prompt response.

  11. Announcing a Managed Released version of Relax, complete with a powerful new feature: Job Parameters. When defining the time and run increment of your Jobs, you can now also pass in Parameters, as a String (hint hint JSON!), which are available in your Relax jobs. Relax also comes pre-loaded with two Relax-usable Apex Classes that leverage this new feature: MassUpdate, and MassDelete. Both let you pass in an arbitrary SOQL query in your Job Parameters, and then perform a Batch Update / Delete operation on those records.

    To install the Managed Released version (1.1), and more details on how to use these new classes, head over to the updated Relax Github repo: https://github.com/zachelrath/Relax

    Relax should be available as a free app on the AppExchange before Dreamforce 2013.

    Also, I’ll be doing a 30-minute session on Relax during Dreamforce 2013! Once Agenda Builder goes live, be sure to register for the session.

  12. Hi, Zack.
    Do you have separate cut-off version that solves only problem #4?
    I was going to write my own solution of this, but it seems like I’m inventing a bicycle if you have already done this.
    However, I am not really currently interested in problems 1, 2, 3 you mentioned.

    1. No I don’t have a separate version — but you can easily still use Relax for 3/4 without ever using the functionality that does 1/2. When creating a new relax__Job__c record, just choose the “Individually Scheduled” option (I think that’s what it’s called), which will ask you to type the name of a Schedulable Apex class and provide a CRON Schedule as a String. You can ignore the other type of Job that Relax lets you create which is used for 1/2.

      https://github.com/zachelrath/Relax

      1. Thanks, Zack, for the quick response.
        I have tried your package and it seems it doesn’t transform existing scheduled jobs into its custom objects, so it doesn’t actually solve my problem, where I want just to collect information about existing scheduled jobs, scheduled by user or programmatically, but not from your custom page or my custom page, mass cancel them before deployment and mass reschedule them after deployment. So I written my own custom page which does only what I actually need. It is not actually so sophisticated as your page, but it satisfies me.
        Also I have written more thoughts about it in my blog here:
        http://patlatus.wordpress.com/2014/01/03/automating-the-process-of-cancelling-and-rescheduling-scheduled-jobs-in-salesforce/

  13. I *LOVE* the concept of Relax, but I can’t seem to get it to behave as I would expect.

    Using the Managed package (v1.4), I submit a normal enough looking Job… with a normal enough looking class (that extends relax.BatchableProcessStep) and what I see is that after 6 Scheduled Apex Jobs appear in Setup => Apex Jobs, the jobs finish and then they don’t resume.

    I think that what’s happening is that the governor limit for Apex Jobs (5) is exhausted and that causes it to fall over.

    I’ve done a bit of research and installed the non-managed code (from github) and seen that this is indeed what’s happening (to support my previous hypothesis of the limit being exhausted)

    I would think that the older jobs would be ‘reaped/aborted’ but that’s just not what I’m seeing.

    I expect that you’re not going to be able to debug the problem based on what I’ve shared, but I’m not sure what would be useful to share 😛

    BTW- I *think* this code:
    https://github.com/zachelrath/Relax/blob/master/src/classes/JobScheduler.cls#L131
    was left over from previous debugging and uses one of the precious, precious SOQL calls 🙂

    1. Hi Daniel, you’re right on about Line 131 🙂

      I think you’re also right about the 6 BatchableProcessStep jobs problem — you can’t have more than 5 Batch Apex jobs concurrently scheduled (until Summer 14 when Salesforce introduces the “Holding” status, which will allow there to be up to 100 Jobs in holding / processing / queued status, with only 5 able to still actually be processing at a given time), no matter how you set them up, whether with Relax or by executing the batches on your own. So I think that the lesson is, make sure that these Jobs don’t all run at the same time, or you’ll have problems.

      Which of course gets down to the major area where Relax needs some improvement (maybe from folks like yourself, which is why i made it Open Source), and that’s in handling Errors and keeping itself alive no matter what. I had some great conversations with folks at Dreamforce 13 after I did my session on Relax about this, and gosh, it is REALLY, REALLY hard to stay native on the platform and guarantee that something like Relax will always, always keep going once started. Apparently Scheduled Jobs are ONLY guaranteed to execute if they are manually scheduled from the UI — if you schedule them programmatically, i.e. using System.Schedule(), then there’s a chance that your jobs may be unexpectedly terminated at random intervals. I’ve experienced this with Relax — after a few days of running fine, Relax’s core scheduling engine will mysteriously stop. System.schedule() just won’t fire, or something like that. No error, it just doesn’t keep going.

      Others suggested the use of various “dead man’s switch” approaches to make sure it doesn’t die, everything from Time-Triggered Workflow rules to an external Heroku server that logs in and checks every 5 minutes to make sure it’s still alive.

      Either way, I’m open to pull requests!

      1. > So I think that the lesson is, make sure that these Jobs don’t all run at the same time, or you’ll have problems.

        I suppose that’s where my problem is.
        I *probably* have misconfigured my job (although I can’t see how), but what I think I’m seeing is the JobScheduler creating a new Apex Job every 30 seconds from just one Relax Job.
        That means after ~180 seconds (30 seconds * 6 jobs) after setting the job up, Relax becomes unresponsive.

        Any advice would be welcome.

        Here is the dataloader data that’s inserted for the job:
        “NAME”,”OWNERID”,”RELAX__ISACTIVE__C”,”RELAX__APEX_CLASS__C”,”RELAX__PARAMETERS__C”,”RELAX__NEXT_RUN__C”,”RELAX__ONLY_RUN_ONCE__C”,”RELAX__ORDER__C”,”RELAX__RUN_INCREMENT__C”,”RELAX__RUN_UNITS__C”
        “Set Collab Score – Sev 1″,”005A0000000gchiIAA”,”true”,”BatchAssignCollabScores”,”1 (Urgent)”,”2014-07-02T10:00:00.000Z”,”false”,”1″,”12″,”Hours”

        I suspect that amongst the thousand things that you have to do, this would be the thousandth, but I’ve been banging my head on this for the last 5 workdays and (again) would appreciate any advice 😛

      2. Daniel,

        I went and ran a test job similar to yours, and while I can’t exactly replicate this, there was one time where I saw an inexplicable clump where the same Batch Apex Class was being run concurrently (3 times) in a small time interval. Not sure what’s causing that, or how to recreate it. It happened once, but it hasn’t happened again. Sounds similar to what you’re seeing.

        Zach

  14. Hi Zach,

    I’ve been using Relax over the past year and love it. But the other day I got an email stating “Could not perpetuate Job Scheduler Process” with the body:
    “Message: Based on configured schedule, the given trigger will never fire.
    Line Number: 121
    Stack Trace:(relax)”

    Is there any way I can retrigger the JobScheduler? I’ve tried via Execute Anonymous but I get Invalid type: JobScheduler because it’s a managed package.

    All of my jobs are set up as Run Individually so they’ve been keeping going but the Last Run time on the Jobs list hasn’t updated since I got the email. What can I do to get this process restarted?

    1. You should be able to restart by deactivating one or more jobs (uncheck the Active box) and then reactivating. If this doesn’t work you may need to deactivate all jobs, then reactivate all jobs. If none of this works, go to the “Scheduled Apex” area in Setup and delete any jobs whose names start with Relax, then go back to the Relax Jobs tab and reactivate your jobs, this should kick off the scheduler again.

  15. Let’s say I have three different groups of Agreggable Relax jobs where one set runs once a day (job d1, job d2), one runs every hour (job h1, job h2), and the other every 15 minutes (job m1, job m2, job m3). Will the “Order” field control which sets of jobs will run first when there are overlaps (midnight and every hour on the hour). Let’s say I have order set as follows

    d1 order = 1
    d2 order = 2

    h1 order = 3
    h2 order = 4

    m1 order = 5
    m2 order = 6
    m3 order = 7

    At midnight, will the jobs run as follows?

    d1, d2, h1, h2, m1, m2, m3

    I don’t currently have a situation like this. I’m mainly curious about how jobs with different schedules interact so I can avoid potential problems.

    BTW, thank you for this tool. Very useful!

    1. Short answer: yes, they should run in the order you indicated. Long answer: In a given pass of the Scheduler, Jobs’ Last Run Time and Next Run Time are checked to see if they qualify for execution at the time when the Scheduler runs, checking for candidate jobs. If multiple Jobs satisfy the criteria for being run at that time, then they will be run in the order specified by the Order field.

  16. I’ve run into a problem with a set of aggregable jobs. There are 3, and they run every 15 minutes. The order numbers are 1, 2, and 3. All three have the same start time. Problem is that I’m seeing multiple runs of some jobs at almost every 15 minute interval. Usually, it will be one extra run of Job 2 or Job 3. Sometimes I’ll get an extra run of both 2 and 3

    I’m using Relax v 1.4. The scheduler appears to be running every minute. There’s is just one scheduler running now although yesterday there was more than one. Any ideas about what I might be doing wrong?

    BTW, if there’s a better place to ask these questions, please let me know.

Leave a reply to radiusx2 Cancel reply