Skip to main content

Quick Tips: Queueable Apex : Loose Coupling with Chainable Interface

Queueable Apex : Loose Coupling with Chainable Interface


Intro to Queueable Apex

Time and again, we come across use cases where we have to either perform an extensive processing, which can breach governor limits, or we want to perform some work asynchronously for improved user experience. Queueable apex provides us a means to create an asynchronous job (An asynchronous job means a piece of work, which is scheduled to run in background, for e.g. you may want to do custom rollup calculations on opportunity save).

Queueable apex is similar to future methods, wherein your future method is queued within a server queue. Server picks up the job and executes it, based on resource availability. However, there are some differences, quite notably:

  1. Queueable apex returns an ID for further enquiry
  2. Queueable apex methods can invoke external API (if Queueable apex class implements Database.AllowsCallouts interface)
  3. Queueable apex methods can enqueue other queueable apex jobs

Say, we have a simple Queueable job, which performs some work,as below:

public class QueueableApexDemo implements Queueable  {
    
    String msg;
    public QueueableApexDemo(String msg){
        this.msg = msg;
    }
    
    public void execute(QueueableContext context) {
        // Your processing logic here      
        system.debug(' This msg is = '  + msg);
    }
}


To execute this Queueable Apex class, you can simply use following apex code (anonymous apex):

QueueableApexDemo a = new QueueableApexDemo('JOB_A');
system.enqueueJob(a);

Chaining Queueable Apex jobs

Now, let's say we have to chain two jobs, say we have to run another job, after completion of initial job.

So, we create another Queuable class, such as:

public class ChainedJob implements Queueable  {
    
    String msg;
    public ChainedJob(String msg){
        this.msg = msg;
    }
    
    public void execute(QueueableContext context) {
        // Your processing logic here      
        system.debug(' ChainedJob msg is = '  + msg);
    }
}


Now, in order to chain these, we'll need to modify initial class QueueableApexDemo as follows:

public class QueueableApexDemo implements Queueable  {
    
    String msg;
    public QueueableApexDemo(String msg){
        this.msg = msg;
    }
    
    public void execute(QueueableContext context) {
        // Your processing logic here      
        system.debug(' This msg is = '  + msg);
        
        ChainedJob job2 = new ChainedJob('CHAINED_JOB_1');
        System.enqueueJob(nextJob);
    }
}


Note: A key limitation to consider here is that Apex allows only one job to be enqueued via a Queueable job. 

Tight coupling with Queueable Apex

Now, in real world, you would not want your first class (QueueableApexDemo) is tightly coupled with second class (ChainedJob). Also, in reality, as you create more complex code, there may be need to dynamically decide jobs to be chained together at runtime.

QueueableChainJob

I created a simple wrapper class to address this complexity around chaining queueable apex jobs at runtime, while keeping individual queueable apex classes loosely coupled. Another key design factor I kept in mind was to not add a complete wrapper on the Queueable apex class, rather extend its capabilities.


public abstract class QueueableChainJob {
    
    private Queueable nextJob;
    
    public void setNextJob(Queueable nextJob){
        //Apex does not allow chaining queueable jobs within Test Context;
        if(Test.isRunningTest() == false){
            this.nextJob = null;
        }
    }
    
    public Queueable getNextJob(){
        return this.nextJob;
    }
    
    public ID enqueueNextJob(){
        ID jobID = null
        if(nextJob != null){
            jobID = System.enqueueJob(nextJob);
        }
        return jobID; 
    }
}


Implement Loose Coupling with Chainable Interface

Now, you can modify your Queuable Apex classes such as:

First class: QueueableApexDemo

public class QueueableApexDemo extends QueueableChainJob implements Queueable  {
    
    String msg;
    public QueueableApexDemo(String msg){
        this.msg = msg;
    }
    
    public void execute(QueueableContext context) {
        // Your processing logic here      
        system.debug(' This msg is = '  + msg);
        
        // Chain this job to next job by submitting the next job
        ID jobID = this.enqueueNextJob();
    }
}

Second Class: ChainJob

public class ChainedJob extends QueueableChainJob implements Queueable {
    
    String msg;
    public ChainedJob(String msg){
        this.msg = msg;
    }
    
    public void execute(QueueableContext context) {
        // Your processing logic here      
        system.debug(' ChainedJob msg is = '  + msg);
        
        // Chain this job to next job by submitting the next job
        ID jobID = this.enqueueNextJob(); 
    }
}

Please note, there are minor differences:
  1. both classes now extend QueueableChainJob abstract class
  2. both classes have execute method calling enqueueNextJob();
Rest of the code remains as-is.

Now, you can run your code as follows:

QueueableApexDemo a = new QueueableApexDemo('JOB_A');
ChainedJob b = new ChainedJob('JOB_B');

a.setNextJob(b);

system.enqueueJob(a);

Similarly, you can chain multiple jobs as needed and add required conditions to add jobs. Sample code below:

QueueableApexDemo nextChainJob;
QueueableApexDemo a = new QueueableApexDemo('JOB_A');
nextChainJob = a;

if(UserInfo.getUserType() == 'Standard'){
    ChainedJob b = new ChainedJob('JOB_B');

    nextChainJob.setNextJob(b);

    nextChainJob = b;
}

In above code, the second job is chained, only if current user's UserType is Standard, else second job is not chained.

The above code is meant for guidance is not tested for all scenarios.

Comments

Popular posts from this blog

Quick Tips: Salesforce default Images

Well, I'm sure a lot of you still rely on using out of the box salesforce images for displaying quick icons within formula fields or even using them within your Visualforce pages. Lately, I realized that a lot of earlier resources are no longer accessible, so I tried to quickly extract all images from Salesforce CSS files and provide a quick reference here. Please note, I've referenced all images from SF servers directly, so if anything changes, the image should stop rendering here. As these images are completely controlled by Salesforce, and in case they change anything, it might lead to image not being accessible. Image path Image /img/samples/flag_green.gif /img/samples/flag_green.gif /img/samples/flag_red.gif /img/samples/color_red.gif /img/samples/color_yellow.gif /img/samples/color_green.gif /img/samples/light_green.gif /img/samples/light_yellow.gif /img/samples/light_red.gif /img/samples/stars_100.gif /img/samples/stars_200.gif /img/samples/stars_300.

Lightning: Generate PDF from Lightning components with in-memory data

I'm sure as everyone is diving into lightning components development, they are getting acquainted with the nuances of the Lightning components framework. As well as, its current limitations. Being a new framework, this is bound to happen. Although we have our users still using salesforce classic, we have started using lightning components framework our primary development platform and Visualforce is considered primarily for rendering lightning components within Classic Service console. Recently, while re-architecting a critical module, we encountered a problem wherein we needed to generate PDF from lightning components. Now, being Javascript intensive framework, it has limited room for such features (may be included in future roadmap). As of now, there is no native feature within the lightning framework to do so (at least I didn't find anything). Common Scenario - Create Visualforce page to retrieve data and generate PDF For scenarios where the data exist within Sa

Quick Tips: Setup SFDX Manually without Admin access

We all have faced challenges while working in different enterprise environments, where there may be lot of controls/ checks/ red-tape to get by. In such situations, getting access to simple tools (even git) can take lot of time. Note: This tutorial is to be followed at your own risk, as it may not be complaint to your organization's IT policies. What is SFDX? SFDX is a command line utility for managing salesforce builds/ deployments. Being command line, it can be easily embedded to automation chains, to help build fully automated build and deployment processes. To get started, refer  https://trailhead.salesforce.com/en/content/learn/trails/sfdx_get_started Setup SFDX on Windows machine without admin access As you may have already realized, SFDX installation needs admin access to one's machine. Which may be a luxury a lot of developers may not have. So, i tried to provide a step-by-step guide to setup SFDX on your computer without any admin access Steps: Note: