6

i have written a future method here is source code

@future(callout=true)
   public static void futureDownloadAttachment(Set<ID> documentsID){
    List<SpringCM_Attachment__c> logs = [Select Id,Object_ID__c,SpringCM_Document_Id__c,Attachment_Id__c From SpringCM_Attachment__c Where Id IN :documentsId];
    System.debug('logs are'+logs);
    for(Integer i=0;i<logs.size(); i++)
     if(logs[i].Attachment_Id__c == null)
    { logs[i] = downloadAttachment(logs[i]);
    update logs[i] ;
    }
   }

   public static SpringCM_Attachment__c downloadAttachment(SpringCM_Attachment__c log){
    System.debug('coming here');
    Http h = new Http();
    HttpRequest req = new HttpRequest();
    req.setEndPoint(SpringCM_Uploader_Settings__c.getOrgDefaults().Heroku_service__c+'/downloadDocument?documentId='+log.SpringCM_Document_Id__c);
    req.setMethod('GET');
    HttpResponse res = h.send(req);
    System.debug('response body is'+res.getBody());   
    AttachmentInfo attachInfo;
   Attachment a;
    if(res.getStatusCode() ==200)
    {   attachInfo = (AttachmentInfo) System.JSON.deserialize(res.getBody(),AttachmentInfo.class);
        log.Status__c = AttachInfo.Status;
        log.Upload_details__c = AttachInfo.detail;

    if(attachInfo.DocumentDownloadResult != null)
 {   a = new Attachment(); 
    a.Body = Blob.valueOf(attachInfo.DocumentDownloadResult);
    a.Name= attachInfo.documentName;
    a.ParentId = log.Object_Id__c;   
     furtherProcess = false;
    insert a;
 }
 }  

    if(res.getStatusCode() != 200)
    {   log.Status__c = 'Error - Heroku';
        log.Upload_details__c = res.getBody().substring(0,2490);
    }       
    log.Object_type__c = String.valueOf(((ID)log.Object_ID__c).getSObjectType());
        if(a != null)
        log.Attachment_ID__c = a.Id;
        return log;
    }

i am getting error You have uncommitted work pending. Please commit or rollback before calling out.how to resolve this issue.Please help

10

This is a very common issue that one encounters

The issue happens you are doing a DML before you do a Callout .To replicate this issue one can try things like

Account acc=new Account();
acc.Name='Test exception';
insert acc;//insert a dummy account

Http h = new Http();//DO a HTTP callout 
HttpRequest req = new HttpRequest();
 req.setEndPoint(SpringCM_Uploader_Settings__c.getOrgDefaults().Heroku_service__c+'/downloadDocument?documentId='+log.SpringCM_Document_Id__c);
req.setMethod('GET');
HttpResponse res = h.send(req);
System.debug('response body is'+res.getBody()); 

Resolution when using button to invoke

This workaround splits the transaction into two separate Ajax processes. The first inserts the record and the second performs the callout and is able to update the newly inserted record.****

   <!-- TestWsCallout.page -->
   <apex:page controller="TestWsCallout" tabstyle="Account">
    <apex:form >
    <apex:actionFunction action="{!InsertRecord}" name="InsertRecord_JS" Rerender="statuses" status="Status1" oncomplete="CallWebService_JS();"/>
    <apex:actionFunction action="{!CallWebService}" name="CallWebService_JS" status="Status2" reRender="statuses, msg"/>
    <apex:outputPanel id="statuses">
        <apex:actionStatus id="Status1" startText="...Inserting Record Into DB..." />
        <apex:actionStatus id="Status2" startText="...Calling Web Service..." />
    </apex:outputPanel>
    <apex:outputPanel id="msg">
        <apex:pageMessages />
    </apex:outputPanel>
    <div><input name="DoAction" class="btn" type="button" value="Do Action" onclick="InsertRecord_JS();return false;"/></div>
</apex:form>

// TestWsCallout.cls
  public class TestWsCallout{
   Account myAccount;

  public PageReference InsertRecord() {
    myAccount = new Account(name = 'Test Account');
    insert myAccount;
    // Calling a Web Service here would throw an exception
    return null;
  }

public PageReference CallWebService() {

    // Execute a call to a Web Service
    HttpRequest req = new HttpRequest();
    req.setEndpoint('http://MyWebService12345678790.com?id=' + myAccount.Id);
    req.setMethod('GET');
    HttpResponse response = new Http().send(req);

    // Simulate an update
    myAccount.Name = 'Test Account 2';
    update myAccount;        
    ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.CONFIRM, 'WebService Called on New Account: ' + myAccount.Name));
    return null;
   }
 }

Resolution when using In Trigger

If your transaction allows you to split your calls,that will be best route.One call will be for DML and other for Callout(Mutiple future callouts)

**Another way will be first do a Callout and then do a DML and even this would also avoid this exception .

  • I am facing the same error. What happen if the callout is made from dml only?[insert acc -> trigger(after insert)-> call @future method -> call callout] In sandbox while testing i am not getting any error, but whiile deploying to production i got this error. please help: see my post here : salesforce.stackexchange.com/questions/183649/… – Archita patnaik Jul 11 '17 at 9:20
1

Make sure you perform your DML before the callout see this salesforce article

  • You just say the opposite to the link you provided. There it says: Web Service Callout may not occur after a DML statement. – RocketR Jul 7 '17 at 8:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.