Put Your Apex To Sleep with Salesforce Asynchronous Callouts
Asynchronous Callouts is a new Apex feature that lets you scale up the number of users using web service callouts to integrate external services to the Salesforce platform.
OK, quick show of hands: who loves web service callouts? I can’t see through the internet, so I’m just going to assume everyone is raising their hands.
Another quick show of hands: who has run into some oddities with making web service callouts from Apex? Again, I can’t see through the internet, but I’m going to assume a few of you raised your hands on this question. There are a few interesting roadblocks that we have put in place for making callouts from Apex.
The new Salesforce Asynchronous Callouts feature will help us remove one of these these roadblocks, and allow you to scale your integration with existing services.
One problem with web service callouts, from the perspective of the multi-tenant service, is long-running threads. We have a large number of threads on each pod to service every one of you and every one of your users. A large number, but a finite number. Because of this finite pool of threads, we have to be sure that there are always some available for the next request that shows up. A callout that takes a long time to return can hold on to a waiting thread for a long time. If an org is calling that endpoint a lot, it can cause issues.
At the very least, blocking a thread for 10-20 seconds is an inefficient use of resources. If you’ve read this far, you are probably a developer, so this inefficiency probably bugs you as much as it bugs me.
You may be calling several different web services, each of which on their own isn’t terribly slow. However, the synchronous callout approach requires you to call them serially, and, when added together, the time for the callouts can become a long time.
We have a limit in place to protect you from another org that starts trying to run lots of these long-running transactions at once. If an org has more than ten transactions in flight that have been going for five seconds, that org is blocked from running any further Apex transactions. This is quite annoying to the org that gets blocked. It’s not really annoying to you, though, since it means that the org didn’t manage to get 20, 30, or 100 threads spun into action and grind our service down to a crawl.
(“Wait, this wasn’t why I raised my hand!” Read on – I’ll discuss a few other things at the end.)
Dolphins in the Tuna Net
There are legitimate use cases for long-running transactions when web services are involved. What if I have a configuration engine on-premise that I would like to integrate? What if I need to communicate with an approval engine that takes forever to spit out a yea or nay?
If you wanted to run an international service center with thousands of agents, and have their UI integrated with long-running back-end processes, you would not be ok. Our limits would snare your use case along with misbehaving orgs.
In the past, our answer has been: go asynchronous, where our queueing mechanism can protect our service. That answer suffices for many operations. It was sub-optimal when we came to integrating long-running web services to a Visualforce page. With a VF page, you have a user waiting, and the added overhead of the queue and the streaming response can tip the user balance from “patiently waiting” to “throwing objects at the screen”.
Introducing: Salesforce Asynchronous Callouts
We needed a way to scale to the needs of the large support center. We came up with Asynchronous Callouts. You may not be running an international service center with thousands of agents, but you, too, may have a use case that can benefit from this new feature.
Asynchronous Callouts works through a call and callback pattern known as a Continuation. (Don’t worry – I had to Google it when it was first suggested, too.) In essence, the Continuation object holds the callout request information and the response from your callout. It is used as the vehicle for launching the callout and returning that information back to your callback method. (The interesting quirk is that the same method can be used to do both the call AND the callback. Head Explode. You don’t have to be that fancy; you can just have a separate callback method.)
The coding pattern for a synchronous callout in a VF action was: build up message payload; make callout; examine response; manipulate data; return to the page.
Now, the Continuation pattern splits this in two.
- First: build up message payload; make callout.
- Second: examine response; manipulate data; return to the page.
Existing code will not need to change very much in order to utilize this pattern. There’s just a small change in terms of encapsulation, a different place to put the callout payload, and a different place from which you pull the response.
How Stuff Works
You are now wondering, “how does this make any difference?” What is happening between the end of method one and the start of method two? In the existing inline-synchronous-callout approach, the thread would be running, waiting, waiting, waiting, etc., and holding that thread resource through the duration of the callout, all while not doing anything.
In the new pattern, your thread is put to sleep while we await the return of your callout.
We are now using a separate server for the web service request. This allows us to release the thread resource, park transaction information in serialized form, and reanimate it when the response has returned. This means you can have a thousand different people simultaneously making callouts that last for 30 seconds. During those 30 seconds, they will not be consuming threads. Thus, we won’t need to block the org for long-running transactions. Hooray!
When you create the Continuation object, you put information in it about your callout request, and the name of the method you want it to callback to when the response has been delivered. The object will be used to find you again when the response is ready. We take care of all of that for you. Hooray!
Visualforce is the main place where Continuations will be used for the initial release. As such, we have modified the action function pattern to handle the call and callback pattern. In the old world, every action function had to return a PageReference, which directed back to the page. Now, the method can return a Continuation object, indicating that it’s not ready to return to the page yet. The callback method can return a PageReference once the response has been handled.
And – check this out – the callback method can also return a Continuation object. This means you can make more than one callout in a single go, firing them off simultaneously, and process the responses as they arrive. Let’s say you are calling web services from the DMV. Or a taxi cab dispatch. Or an airport baggage system. Or anything else that makes you wait interminably. You can kick them all off at once, and parallelize the wait time to reduce the end user pain. Hooray!
Ask your doctor if Asynchronous Callouts are right for you
Despite the rejoicing in the last section, it is important to note that 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 VF page being used by lots of users that is integrating, real-time, to a heavyweight external system.
Sign Me Up?
We are running a pilot with this feature, starting with the Spring ‘14 release. We will probably make the feature generally available in Winter ‘15 or Spring ‘15 – we need to make sure that the feature scales to our expected volumes before we let everybody try to break it. If you are interested in participating in the pilot, contact your person-you-contact-for-these-kinds-of-things to submit a nomination on your behalf (e.g., CSE, ISV enablement guru, customer support, etc.) As with all pilot programs, we will not be able to include everyone who is interested, but we have to know that you’re interested to include you.
You may have raised your hand for other reasons, and we are trying to address many of these.
- There is a published limit of 20 callouts to one endpoint, which is confusing, so it is being removed in Winter ‘15.
- There is a limit to the number of callouts in a transaction. We are examining if we can relax or remove this limit in Winter ‘15.
- There is a limit to the size of a message that can be sent and/or received. We are also examining if we can relax or remove this limit – or just consolidate it with the existing heap limit – in Winter ‘15.
- There is a great JSON parser, but no analogue for XML. We’ve looked at the effort in building this as part of the product rather than have each of you build your own parser, like we have done for JSON.
- Callouts don’t perform magic, so you still need to write Apex code. This one we won’t fix. That said, we know there are other items out there, and we’ll tackle them one-at-a-time in the attempt to make your life as a developer easier.