Queueable Apex Classes: Beyond @future Methods

Introduction

Queueable Apex classes aren’t the newest feature in Salesforce, but they are in my opinion one of the most useful. I hadn’t used them or even known of their existence until very recently when I ran into a roadblock on a project while trying to use @future methods (which are always asynchronous) in a synchronous manner!

Video Breakdown

In the video we will…

  • Consider a few advantages of Queueable Apex
  • Talk about our use case and why chaining is necessary with Asynchronous methods
  • Build a class that performs a web service callout
  • Build two Queueable Apex classes, one of which implements the web service callout, the other which is called via a chain execution
  • See how to monitor the execution of those jobs

@future METHODs vs. Queueable APEX CLASSes

Queueable Apex classes are a very clean way to schedule asynchronous jobs to run within Salesforce. It wouldn’t be wrong to consider them a superset of the functionality available in @future methods, as they can do essentially everything a future method can do, plus the following:

  • Non-Primitive Types: the methods within a queueable class have access to member variables which can be sObjects or custom Apex objects that you’ve created.
  • Chain Executions. This was completely absent with future methods. One job can execute another job, allowing you to create a chain of actions — ie. dependent actions.
  • Job Tracking: get an ID for each job and be able to monitor its execution rather than relying on debug logs or custom notifications generated from @future methods.

Code Snippets From the Video

Web Service Callout Class

This class hits a mockaroo API that returns a JSON object. This is meant to mimic a government or third-party database (in this case, Argentina’s government’s “AFIP” API) that provides data on companies: their addresses, industries, etc.

Just a reminder, if this type of code looks foreign to you, consider watching the video and reading the post about Apex REST Endpoints.

public class AFIP_Mock_Request {

    private static String BASE_URL = 'https://api.mockaroo.com/api/generate.json';
    private static final String API_KEY = 'c3b36a70';
    
    public ResponseWrapper Response;
    
    public AFIP_Mock_Request(String businessId) {
                
        this.Response = (ResponseWrapper)
            JSON.deserialize(
                getCalloutResponse(businessId), 
                AFIP_Mock_Request.ResponseWrapper.class
            );
        
    }
    
    String getCalloutResponse (String businessId) {
        
	    HttpRequest req = new HttpRequest();
        
        req.setEndpoint(BASE_URL + '?key=' + API_KEY + '&schema=Afip_Mock&count=1');
        req.setMethod('POST');
        
        Http h = new Http();
	    HttpResponse res = h.send(req);
    	return res.getBody();
        
    }
    
    public class ResponseWrapper {
        public String Company_Name;
        public String Tax_Condition;
		public String Street_Address;
        public String City_Name;
        public String State_Name;
    }
    
}

Our First Queueable Class – EnrichLeadData

Which makes a callout using the class above and updates a Lead with the resulting information. Note: implements, along with Queueable, Database.AllowsCallouts.

public class EnrichLeadData implements Queueable, Database.AllowsCallouts {

    private String businessId;
    private Lead leadToUpdate;
    
    public EnrichLeadData(Id leadId, String bId) {
        this.businessId = bId;
        this.leadToUpdate = [
            SELECT Id, Company, Tax_Condition__c, Address 
            FROM Lead 
            WHERE Id =: leadId
        ];
    }

    public void execute(QueueableContext context) {

        AFIP_Mock_Request afipRequest = new AFIP_Mock_Request(this.businessId);
		        
		this.leadToUpdate.Company = afipRequest.Response.Company_Name;
        this.leadToUpdate.Tax_Condition__c = afipRequest.Response.Tax_Condition;
        this.leadToUpdate.Street = afipRequest.Response.Street_Address;
        this.leadToUpdate.City = afipRequest.Response.City_Name;
        this.leadToUpdate.State = afipRequest.Response.State_Name;

        try {
	        update this.leadToUpdate;            
            Id callbackJobId = System.enqueueJob(new ConvertEnrichedLead(this.leadToUpdate.Id));
        } catch (Exception e) {
            System.debug(e.getMessage());
        }

    }
    
}

Our Second Queueable Class – ConvertLead

Attempts to convert the now-enriched lead. This class’ constructor is called within the class directly above – creating a chain execution. This is necessary because we wouldn’t want to convert our lead automatically if it didn’t have the additional fields that are filled out by the web service callout.

public class ConvertEnrichedLead implements Queueable {

    private Lead leadToUpdate;
    
    public ConvertEnrichedLead(Id leadId) {
		this.leadToUpdate = [SELECT Id FROM Lead WHERE Id =: leadId];
    }
    
    public void execute(QueueableContext context) {
    
        LeadStatus convertStatus = [
            SELECT Id, MasterLabel 
            FROM LeadStatus 
            WHERE IsConverted = TRUE LIMIT 1
        ];
        
        Database.LeadConvert lc = new Database.LeadConvert();
        lc.setLeadId(this.leadToUpdate.Id);
        lc.setConvertedStatus(convertStatus.MasterLabel);
        
        Database.LeadConvertResult results = Database.convertLead(lc);
        
        if (!results.isSuccess())
	        System.debug(results.getErrors());
        
    }
    
}

That’s all! Thanks for watching. You can find the official documentation here.

Add comment

Recent Posts

Categories