-1

Callout class

Public class calloutValidation{
    public static string CalloutCheck(String Email{
        try{
        //There are some logic 
            HttpRequest req = new HttpRequest();
            HttpResponse res = new HttpResponse();
            req.setMethod('POST');
            req.setEndpoint('callout:xxx');
            req.setHeader('Content-Type', 'application/json');
            req.setHeader('xxx', 'xxx');
            req.setBody(reqBody);
            System.debug(req);
            System.debug(req.getEndpoint());
            if (!Test.isRunningTest()) {
                res = new http().send(req);
                System.debug(res);
            }
            return res.getBody();
        }
        catch(CalloutException exp){
            return exp.getMessage();
        }
    }
}

Batch class

public with sharing class xxxx implements Schedulable, Database.Batchable<sObject> {
    public Database.QueryLocator start(Database.BatchableContext bc) {
        return 'select id,Email from Contact Where Email != null';
    }
    
    public void execute(Database.BatchableContext bc, List<Contact> contactList){
        // process each batch of records
        EmailStatusValidationQueueable Queueable = new EmailStatusValidationQueueable(contactList);
        System.enqueueJob(Queueable);

    }

    public void finish(Database.BatchableContext bc){

    }
public with sharing class EmailStatusValidationQueueable implements Queueable,Database.AllowsCallouts {
public List<Contact> contactList;
public EmailStatusValidationQueueable(List<Contact> conList){
    contactList = conList;
    System.debug('contactList EmailStatusValidationQueueable: ' +contactList);
}
public void execute(QueueableContext context) {
    // awesome code here
    Integer sentCount = 0;
    Boolean hitLimit = false;
    List<Contact> updateContact = new List<Contact>();
    for (Contact con : contactList) {
        if (Limits.getCallouts() == Limits.getLimitCallouts()) {
            hitLimit = true;
            break;
        }

        // Do your callout
        String res= calloutValidation.CalloutCheck(con.Email);
        System.debug('res : ' +res);
        if(res != null){
            Map<String, Object> resultJsonData = (Map<String, Object>)JSON.deserializeUntyped(res);
            System.debug('resultJsonData: ' +resultJsonData);
            if(resultJsonData.get('message') != null  && resultJsonData.get('message') == 'OK'){
                con.xxxx = 'Validated';
                System.debug('resultJsonData success');
                updateContact.add(con);
                System.debug('updateContact ' +updateContact);
            }else{
                System.debug('resultJsonData Fail');
            }
        }
        // Track how many leads have been processed
        sentCount++;
    }

    List<Database.SaveResult> result = Database.update(updateContact, false);
    system.debug('result '+result);

    for (Database.SaveResult r : result)

    {
        if (!r.isSuccess())
        {
            system.debug('not isSuccess ');
            for (Database.Error e : r.getErrors())
            {
                system.debug('Error'+e);
            }
        }
    }

    if (hitLimit) {
        // Need to chain this queueable to finish processing. First clean up
        // the list of leads needing a callout, removing all those that have
        // been sent already
        for (Integer index = 0; index < sentCount; index++) {
            contactList.remove(0);
        }

        // Now ensure the remainder get processed by simply re-enqueuing this
        // queueable with its adjusted state
        System.enqueueJob(this);
    }


}

}

  1. There is a batch class which will take all email in contact .(org have more than 4 lakh) Then from that batch class I need to pass each of email to this calloutValidation class and do the Api callout.(Because Post body support only one email at a time)

  2. Can I do a for loop inside execute() method in batch and call the callout class by passing each contact email? Updated--->this only execute 7 records

callout inside for loop This is similar but I need support how can i apply that to my one.

5
  • 1
    Yes, it is possible and a simple internet search for "batch callout apex loop" returns a lot of examples. There are syntax problems in your code and things missing, like "Database.AllowsCallouts". There are many things to consider like the number of callouts you can make per batch run is 100. If I were you I'd try a little harder, possibly do some Trailheads and then come back with a more precise question. Commented Dec 7, 2023 at 9:15
  • Thanks @FelixvanHove for the comment.
    – SFL
    Commented Dec 7, 2023 at 9:21
  • @FelixvanHove my callout class is not a batch.It's a notmal class
    – SFL
    Commented Dec 7, 2023 at 9:36
  • 1
    the limit is 100 callouts per transaction, each batchable execute() invocation starts a new transaction
    – cropredy
    Commented Dec 7, 2023 at 16:32
  • @cropredy Thank you for the comment and suggestion ,When I give 100 it's not running for all data. And stop in ! batch size when I look into Apex job in Org. I tried with 1 also in execute method.
    – SFL
    Commented Dec 8, 2023 at 12:55

1 Answer 1

0

I would suggest that your batchable execute() pass the list of objects to a Queueable class (via its constructor)

  • The queueable class would take the first object off the list
  • Make the callout and do whatever DML is required
  • Enqueue the Queueable class again, passing to its constructor the list of objects minus the object just processed.

Then your batchable execute() method can process 200 objects per transaction but each queueable does only one callout and so would not be subject to a Limits exception on # of callouts or total time for all callouts

There are more sophisticated versions of this pattern

5
  • highly appreciate and thanks for the details guidance you gave a new person like me. I am doubt to make that callout class to Queueable because that is a Util class which use for lot of synchronous UI work. If i make it as Queueable it will be a asynchronous .Is it?. Callout is a utill class and I am using that class to validate all my existing data in org by creating schedule class ,But now I am facing limit issue.
    – SFL
    Commented Dec 9, 2023 at 3:57
  • queueable is async -- it makes the callout and then updates the database with callout results; has async limits. The queueable can invoke your Util class that does the callout and upon return update the database before enqueueing itself with the remaining list.
    – cropredy
    Commented Dec 10, 2023 at 4:32
  • Thanks.Will try and let you know.
    – SFL
    Commented Dec 10, 2023 at 5:25
  • Still I can see that it's running only one batch.I updated the code in Question to current code
    – SFL
    Commented Dec 10, 2023 at 6:24
  • You've made your queueable harder than it has to be - do only one callout for one contact, update the database, then enqueue with remaining contacts. Use the compter as your servant rather than writing complicated Limits checking logic
    – cropredy
    Commented Dec 11, 2023 at 17:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .