Apex Run multiple batch jobs sequentially

We can run 3 batch jobs sequentially by incrementing the jobCounter and passing the integer (job index) into the batch scope

This can be increased to any amount of batch jobs, the problem I solved was able to update the Contact and disable Users in the same code running as different batch job.

As you cannot call @future in a batch method this solves by running each update in their own batch = transaction 👍🏻

global with sharing class App_Job_Account_Delete implements System.Schedulable, Database.Batchable<Integer>, Database.Stateful, Database.AllowsCallouts  {

    private List<JobError> jobErrors = new List<JobError>();

    global Integer jobCounter = 1;

    public void execute(SchedulableContext sc) {
        Database.executeBatch(this, jobCounter);

    public Integer[] start(Database.BatchableContext context) {
        return new Integer[] {jobCounter};

    public void execute(Database.BatchableContext context, Integer[] scope)     {
            if (isSandbox() || Test.IsRunningTest()){
                if(scope[0] == 1) {
                    //add your code here to run as part of 1st batch
                } else if (scope[0] == 2){
                    //add your code here to run as part of 2nd batch
                }  else if (scope[0] == 3){
                    //add your code here to run as part of 3rd batch
            } else {
                JobError jobError = new JobError();
                jobError.message = 'Environment Error: Job will only run on dev and automation environment';
                jobError.records = new List<SObject>();
        } catch (Exception ex){
            JobError jobError = new JobError();
            jobError.records = new List<SObject>();
            jobError.message = 'Exception: ' + ex.getTypeName() + ': ' + ex.getMessage()  + ' -- ' + ex.getCause();

    public void finish(Database.BatchableContext context){
        if (jobCounter<3){
            Database.executeBatch(this, jobCounter);

    public class JobError{
        public String message;
        public List<SObject> records;

    public void setJobError(List<JobError> jobErrors){
        this.jobErrors = jobErrors;

    public static Boolean isSandbox() {
        if ([SELECT IsSandbox FROM Organization LIMIT 1].IsSandbox && ('Dev'.equalsIgnoreCase(CustomSettings.Environment__c) || 'Automation'.equalsIgnoreCase(CustomSettings.Environment__c))){
            return true;
        } else {
            return false;

Run the code as

Id batchprocessid = Database.executeBatch(new App_Job_Account_Delete());

Apex Comparator compare multiple object fields

Sorting a list of Analysis messages first by boolean and then integer. First we will order by condition and then order. All records where condition is true is will be on top in descending order on top followed by all false condition in descending order.

SummaryAnalysisMessages object to sort

public class SummaryAnalysisMessages {
		private String title;
		private String description;
		private Integer order;
		private Boolean condition;

		public SummaryAnalysisMessages(String title, String description, Integer order, Boolean condition){
			this.title = title;
			this.description = description;
			this.order = order;
			this.condition = condition;

		public Boolean getCondition(){
			return condition;

		public Integer getOrder(){
			return order;

Compare object by condition and then order

public class SummaryAnalysisMessagesCompare extends App_Comparator {
    public override Integer compare(Object a, Object b) {
			SummaryAnalysisMessages aSummaryMessage = (SummaryAnalysisMessages)a;
			SummaryAnalysisMessages bSummaryMessage = (SummaryAnalysisMessages)b;

      Integer summaryMessage1 = aSummaryMessage.getCondition() ? 1 : 0;
      Integer summaryMessage2 = bSummaryMessage.getCondition() ? 1 : 0;

			Integer compareInt = summaryMessage2 - summaryMessage1;
      if (compareInt == 0) {
          compareInt = aSummaryMessage.getOrder() - bSummaryMessage.getOrder();
      return compareInt;

Test class to test order

@isTest static void testSummaryAnalysisMessagesCompare(){
		SummaryAnalysisMessages summaryAnalysisMessage1 = new App_Chart.SummaryAnalysisMessages('1', '', 1, false);
		SummaryAnalysisMessages summaryAnalysisMessage2 = new App_Chart.SummaryAnalysisMessages('2', '', 2, true);
		SummaryAnalysisMessages summaryAnalysisMessage3 = new App_Chart.SummaryAnalysisMessages('3', '', 3, false);
		SummaryAnalysisMessages summaryAnalysisMessage4 = new App_Chart.SummaryAnalysisMessages('4', '', 4, true);

		List<SummaryAnalysisMessages> assetAllocationSummaryList = new List<SummaryAnalysisMessages>{summaryAnalysisMessage1, summaryAnalysisMessage2, summaryAnalysisMessage3, summaryAnalysisMessage4};

		App_Comparator.sort(assetAllocationSummaryList, new App_Chart.SummaryAnalysisMessagesCompare());
		System.assertEquals(assetAllocationSummaryList.get(0).getOrder(), 2);
		System.assertEquals(assetAllocationSummaryList.get(1).getOrder(), 4);
		System.assertEquals(assetAllocationSummaryList.get(2).getOrder(), 1);
		System.assertEquals(assetAllocationSummaryList.get(3).getOrder(), 3);

Spring MVC form with multiple submit buttons

<div class="codeContainer">
	<form method="post" action="/login/apex/save/${apexType}/${currentId}">
		<textarea name="code" id="code">${body}</textarea><br/>
		<div class="btn-group">
			<input type="submit" value="Save" name="save" class="btn btn-primary">
			<input type="submit" value="Share" name="share" class="btn btn-primary">
    @RequestMapping(method = RequestMethod.POST, value = "/save/{type}/{id}")
    public String updateClassDetail(@PathVariable("id") String id, @PathVariable("type") String type,
                    @RequestParam("code") String code, Map<String, Object> map,
                    @RequestParam(required=false, value="save") String save,
                    @RequestParam(required=false, value="share") String share){

  if (save!=null){
  } else if (share!=null){