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
Roger WickiRoger Wicki 

@future(callout=true) call until worked or > MAX_TRIES

Dear community

I have a case that I create a callout to an external service that will result in an attachment uploaded to Salesforce. Sometimes, I get a 504 Timeout on the HTTP request but still the attachment is created. So far, I am sending myself an email so I can check whenever an error has occured and if necessary, create the attachment manually. Now I want to implement a feature, that checks on a 504 code whether the attachment has been created and if not, try the call again. The latter poses a problem as @future tagged methods do not allow to call another @future method. So I need a way to kind of tell salesforce to repeatedly try to execute this http request as long as the attachment is not present and max tries has not been exceeded. Optimally, it would also increase the time between tries.

This is what I have:
global class FutureCallout
{
	@TestVisible private static final Integer MAX_TRIES = 8;
	
	@future(callout=true)
	public static void generateCongaDocument(Id opportunityId, Id attachParentId, String sessionId, Integer tries) {
		
		Http http = new Http();
		HttpRequest request = new HttpRequest();
		request.setEndpoint(CongaDocumentCreator.getCongaUrl(opportunityId, true, true, true, sessionId, attachParentId));
		request.setMethod('GET');
		request.setTimeout(120000);
		HttpResponse response;
		if ( !Test.isRunningTest() ) {
			response = http.send(request);
		} else {
			response = new HttpResponse();
			response.setStatusCode(200);
		}
		// Handle erraneous responses
		if (response.getStatusCode() == 504) {
			if ( tries <= MAX_TRIES && !InstallmentCreator.isAttachmentPresent(attachParentId) ) {
				FutureCallout.generateCongaDocument(opportunityId, attachParentId, sessionId, ++tries);
			}
		} else if ( response.getStatusCode() != 200 ) {
			ArcUtil.sendAdminNotification('Document Creation with Barcode for Installment ' + attachParentId + ' failed with HTTP Response Code ' + response.getStatusCode() +
			'. Use the developer console to try creation again. Additional Info:\n\n---\n\nStatus:\n' + response.getStatus() + '\nBody:\n' + response.getBody() +
			'\n\nRequest:\n' + request.getEndpoint());
		}
	}
}
Is there any way to do so? Can I schedule a job somehow and pass the job information to be processed?
Amit Singh 1Amit Singh 1
Hi Roger,

Try by creating another method which is not future and from that method call your future method. The method you created will be called whenever status code is 504.

Please try the below code hope it will help.
 
global class FutureCallout
{
    @TestVisible private static final Integer MAX_TRIES = 8;
    
    @future(callout=true)
    public static void generateCongaDocument(Id opportunityId, Id attachParentId, String sessionId, Integer tries) {
        
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint(CongaDocumentCreator.getCongaUrl(opportunityId, true, true, true, sessionId, attachParentId));
        request.setMethod('GET');
        request.setTimeout(120000);
        HttpResponse response;
        if ( !Test.isRunningTest() ) {
            response = http.send(request);
        } else {
            response = new HttpResponse();
            response.setStatusCode(200);
        }
        // Handle erraneous responses
        if (response.getStatusCode() == 504) {
            if ( tries <= MAX_TRIES && !InstallmentCreator.isAttachmentPresent(attachParentId) ) {
                FutureCallout.Callfuture(opportunityId, attachParentId, sessionId, ++tries);
            }
        } else if ( response.getStatusCode() != 200 ) {
            ArcUtil.sendAdminNotification('Document Creation with Barcode for Installment ' + attachParentId + ' failed with HTTP Response Code ' + response.getStatusCode() +
            '. Use the developer console to try creation again. Additional Info:\n\n---\n\nStatus:\n' + response.getStatus() + '\nBody:\n' + response.getBody() +
            '\n\nRequest:\n' + request.getEndpoint());
        }
    }
    public static void Callfuture(Id opportunityId, Id attachParentId, String sessionId, Integer tries){
        FutureCallout.generateCongaDocument(opportunityId, attachParentId, sessionId, ++tries);
    }
}

Thanks,
Amit.
Roger WickiRoger Wicki
Hmm, worth a thought. Can I have a callout in a synchronous method? I thought this was not possible. Also, this would mean if I get a 504, it would just try in fast succession (every 2 minutes), which is not worth much if the server is down for half an hour or so.