Apex Continuations: Asynchronous Callouts from Visualforce Pages

Asynchronous Callouts, generally available with Spring '15, are a new Apex feature that allow you to escape the limit of ten concurrent long-running callouts, where 'long-running' means 'more than five seconds'. Discover how you can use Asynchronous Callouts with JavsScript Remoting.

Last May, Josh Kaplan wrote about Asynchronous Callouts, a new Apex feature that would allow you to escape the limit of ten concurrent long-running callouts, where ‘long-running’ means ‘more than five seconds’. At that time, Asynchronous Callouts were entering pilot, but they are now generally available with Spring ’15!

As Josh explained, Asynchronous Callouts work through a pattern called a Continuation; your controller creates its HTTP request as it normally would, but, instead of firing it off there and then, you create a Continuation object, pass the HTTP request and an Apex callback method to the Continuation, and return it to the platform for processing.

Josh did a great job explaining the internal workings of Asynchronous Callouts, and the documentation shows exactly how to make long-running callouts in an action method, so I’ll show you here how to make an asynchronous callout via JavaScript Remoting. Here’s the @RemoteAction method; it accepts arguments as normal, but returns a Continuation object, rather than the response to return your JavaScript code.

// Called via JavaScript Remoting
@RemoteAction
public static Object callService(Integer count){
    // Make an HTTPRequest as we normally would
    // Remember to configure a Remote Site Setting for the service!
    String url = 'https://node-count.herokuapp.com/'+count;
    HttpRequest req = new HttpRequest();
    req.setMethod('GET');
    req.setEndpoint(url);

    // Create a Continuation for the HTTPRequest        
    Continuation con = new Continuation(60);
    con.state = con.addHttpRequest(req);
    con.continuationMethod = 'callback';        

    // Return it to the system for processing
    return con;
}

Node-Count, is a very simple Node.js server process on Heroku that counts to a given number, returning a number every second.

When the HTTP request completes, your Apex callback is invoked with whatever state you gave it. In the above code, addHttpRequest() returns a label that identifies the HTTP request. You can associate multiple requests with a Continuation, but in this sample, I just have one, so I set the Continuation’s state to the label, so I can easily access it later.

Here’s the Apex callback method; since state holds the label for the HTTP request, I just pass it to Continuation.getResponse() to get the corresponding HTTP response.

public static Object callback(Object state) {
    HttpResponse response = Continuation.getResponse((String)state);

    Integer statusCode = response.getStatusCode();
    if (statusCode >= 2000) {
        return 'Continuation error: ' + errors.get(statusCode);
    }

    return response.getBody();
}

Once you have your HTTP response, it’s pretty much business as usual. There are some new error codes to cover various situations specific to Asynchronous Callouts, so you should test for them and take appropriate action:

  • 2000: The timeout was reached, and the server didn’t get a chance to respond.
  • 2001: There was a connection failure.
  • 2002: Exceptions occurred.
  • 2003: The response hasn’t arrived (which also means that the Apex asynchronous callout framework hasn’t resumed).
  • 2004: The response size is too large (greater than 1 MB).

Josh wrote last May:

Not everybody will have a use for this pattern. You may not want or need to go through the overhead of using the Continuation object and the Asynchronous Callouts framework. If your web service calls return quickly, and you are only calling them serially, and you don’t have thousands of concurrent users, an inline synchronous callout is still a valid approach to integration. The main consumer target is a Visualforce page being used by lots of users that is integrating, real-time, to a heavyweight external system.

If that last sentence rings any bells, Asynchronous Callouts might be just what you need!

Leave your comments...

Apex Continuations: Asynchronous Callouts from Visualforce Pages