function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ForceRookieForceRookie 

How to fix callout error -- You have uncommitted work pending. Please commit or rollback before calling out?

I'm doing an upload attachment to AWS, but I'm getting this error -- 'You have uncommitted work pending. Please commit or rollback before calling out'
How do I fix this?

@AuraEnabled
    public static void savePDupcsSettings(ForUploadCustomSettings__c upcsSet, String recId){
        ForUploadCustomSettings__c upcs = new ForUploadCustomSettings__c();
        upcs = upcsSet;
        if (upcs.Objects__c != null) {
			if (recordId != null) {
                upcs.Name = upcs.Objects__c +'-'+ upcs.Fields__c +'-'+ upcs.Value__c;
			    update upcs;
            } else {
                ForUploadCustomSettings__c newVal = new ForUploadCustomSettings__c();
                newVal.Name = upcs.Objects__c +'-'+ upcs.Fields__c +'-'+ upcs.Value__c;
                newVal.Objects__c = upcs.Objects__c;
                newVal.Fields__c = upcs.Fields__c;
                newVal.Value__c = upcs.Value__c;
                insert newVal;
            }
        }
        
        String stage = 'Closed Won';
        ForUploadCustomSettings__c csList = [SELECT Id, Id, Objects__c, Fields__c, Value__c 
                                                              FROM ForUploadCustomSettings__c 
                                                              WHERE Value__c = :stage LIMIT 1];
        if (csList != null) {
            Set<Id> Ids = new Set<Id>();
			for (Opportunity opp : [SELECT Id, Name FROM Opportunity WHERE IsClosed = true AND IsWon = true]) {
				Ids.add(opp.Id);
			}

			String formattedDateString = Datetime.now().format('EEE, dd MMM yyyy HH:mm:ss z');   
			String host = 's3.amazonaws.com/';
			String method = 'PUT';
			
			HttpRequest req = new HttpRequest();
			Http http = new Http();

			List<Attachment> att = [SELECT Id, Name, Body, ContentType FROM Attachment WHERE ParentId IN :Ids];
			List<AWScredentialsSettings__c> creds = [SELECT Id, ClientKey__c, SecretKey__c, BucketName__c FROM AWScredentialsSettings__c LIMIT 1];
			if (!att.isEmpty() && !creds.isEmpty()) {
				String bucketname = creds[0].BucketName__c;
				String key = creds[0].ClientKey__c;
				String secret = creds[0].SecretKey__c;
				String attachmentBody = EncodingUtil.base64Encode(att[0].Body);
				String filename = att[0].Name;
				
				req.setMethod(method);
				req.setEndpoint('https://' + host + bucketname + '/' + filename); // The file should be uploaded to this path in AWS -- Opportunity/Salesforce Id/Secret Files/filename
				req.setHeader('Content-Length', String.valueOf(attachmentBody.length()));
				req.setHeader('Content-Encoding', 'UTF-8');
				req.setHeader('Content-type', att[0].ContentType);
				req.setHeader('Connection', 'keep-alive');
				req.setHeader('Date', formattedDateString);
				req.setHeader('ACL', 'public-read');
				req.setBody(attachmentBody);
				
				String stringToSign = method+'\n\n\n'+ att[0].ContentType + '\n' + formattedDateString +'\n/'+ bucketname +'/' + filename;
				Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign),blob.valueof(secret));
				String signed  = EncodingUtil.base64Encode(mac);
				String authHeader = 'AWS' + ' ' + secret + ':' + signed;
				req.setHeader('Authorization',authHeader);
			}
			
			HTTPResponse res = http.send(req);
			System.debug('*Resp:' + String.ValueOF(res.getBody()));
			System.debug('RESPONSE STRING: ' + res.toString());
			System.debug('RESPONSE STATUS: ' + res.getStatus());
			System.debug('STATUS_CODE: ' + res.getStatusCode());
        }
    }
Meghna Vijay 7Meghna Vijay 7
Hi,

Perform DML operation after the callout. In you case shift this code from top to bottom.
ForUploadCustomSettings__c upcs = new ForUploadCustomSettings__c();
        upcs = upcsSet;
        if (upcs.Objects__c != null) {
			if (recordId != null) {
                upcs.Name = upcs.Objects__c +'-'+ upcs.Fields__c +'-'+ upcs.Value__c;
			    update upcs;
            } else {
                ForUploadCustomSettings__c newVal = new ForUploadCustomSettings__c();
                newVal.Name = upcs.Objects__c +'-'+ upcs.Fields__c +'-'+ upcs.Value__c;
                newVal.Objects__c = upcs.Objects__c;
                newVal.Fields__c = upcs.Fields__c;
                newVal.Value__c = upcs.Value__c;
                insert newVal;
            }
        }
Hope it helps, if it does mark it as solved so that it can hep others too.

Thanks
 
PawanKumarPawanKumar
you can wrap your webservices call into @Future method / you can use queueable interface too.
ForceRookieForceRookie
How will I do it on Queueable class and call on Controller?
can you teach me please?