Remote Process Invocation – Continuations
When you implement Salesforce, you frequently need to integrate it with other applications. Although each integration scenario is unique, there are common requirements and issues that developers must resolve. This document describes one of the patterns (and others coming soon!!) for these common integration scenarios.
Each pattern describes the design and approach for a particular scenario rather than a specific implementation. This pattern, called Remote Process Invocation – Continuations, takes the common usecase of having an external system that is used to contain and process orders. In this scenario, you use Salesforce to track leads, manage your pipeline, create opportunities, and capture order details that convert leads to customers. After the order details are captured in Salesforce, an order needs to be created in the remote system, and the remote system manages the order to its conclusion.
When you implement this pattern, Salesforce makes a call to the remote system to create the order, and then waits for successful completion of that call. To signify successful completion of the call, the remote system synchronously replies with the order status and order number. As part of the same transaction, Salesforce updates the order number and status internally. The order number is used as a foreign key for any subsequent updates to the remote system.
The Problem with Synchronous Requests
The multitenant Force.com platform uses governor limits to ensure that system resources are available to all customers, and to prevent any one customer from monopolizing them. One limit that customers frequently reach is the concurrent request limit. When a synchronous Apex request runs longer than five seconds, it counts against this limit. Each org is allowed 10 concurrent long-running requests.
The most common causes of limit errors are synchronous web service callouts. Often the long-running transactions are identified late in the process of the project during performance testing, giving limited room for change. How do you design your system to handle long-running services?
Things to Consider in this Pattern
There are various forces to consider when applying solutions based on this pattern:
- Does the call to the remote system require Salesforce to wait for a response before continuing processing? In other words, is the call to the remote system a synchronous request-reply or an asynchronous request?
- If the call to the remote system is synchronous, is it taking over five seconds on average to send a response?
- Is the message size relatively small or large?
- Is the integration based on the occurrence of a specific event, like a button click in the Salesforce user interface? And, is the event UI-synchronous – i.e., the user waits for a response before moving to the next screen?
Asynchronous Apex to the Rescue!
The Apex Asynchronous Callout Framework enables you to make callouts from a Visualforce page to an external web service, and get responses asynchronously. By making asynchronous callouts, your org is no longer restricted by the limit of 10 synchronous requests lasting longer than five seconds. Your asynchronous callouts do not consume unnecessary platform resources while the system is waiting for a response. As a result, you can make more callouts than when using synchronous callouts.
The order of operations goes like this:
- The Visualforce Page button action is implemented in an Apex controller method.
- The action method creates a continuation and then returns it.
- After the request is sent to the service, the Visualforce request is suspended.
- The user waits for the external service to return a response before continuing to use the page and invoke new actions.
- The Visualforce request resumes when the page receives this response.
The following diagram illustrates an Apex asynchronous process invocation using Apex calls.
In this scenario:
- The user initiates an action on the Visualforce page (for example, clicks a button).
- The browser performs an HTTP POST that in turn performs an action on the corresponding Apex controller.
- The controller calls the external service by using a continuation instance in your Visualforce action method. For this you will need to associate the continuation object to an external callout.
- The method that invokes the callout returns the continuation object to instruct Visualforce to suspend the current request after the system sends the callout and gets the response.
- The continuation object holds the details of the callout to be executed asynchronously.
- The remote system’s response is returned to the Apex controller, which processes the response, updates any data in Salesforce as required, and re-renders the page. In cases where subsequent state needs to be tracked, the remote system returns a unique identifier that’s stored on the Salesforce record.
Applying the Pattern
A typical Salesforce application that benefits from asynchronous callouts is one with a Visualforce page where users click a button to get data from an external web service.
For example, the Visualforce page might get warranty information for a certain product. This page can be used by thousands of agents in the org. One hundred agents might simultaneously click the same button to process warranty information for products. These hundred simultaneous actions exceed the limit of concurrent long-running requests of 10. But with asynchronous callouts, the requests aren’t subject to this limit and can all be executed.
Not everybody has a use for this pattern. You may not want or need the overhead of using the continuation object and the Asynchronous Callouts framework. If your web service calls return quickly, you’re calling them serially, and you don’t have thousands of concurrent users, an inline synchronous callout is still a valid approach to integration.
The ideal consumer is a Visualforce page being used by lots of users that is integrating real-time to a heavyweight external system.
Error Handling and Recovery
An error handling and recovery strategy is part of a sound overall solution.
- Error handling—When an error occurs (exceptions or error codes are returned to the caller), error handling is managed by the caller. —For example, an error message that’s displayed on the end user’s page or logged to a table requiring further action.
- Recovery—Changes aren’t committed to Salesforce until the caller receives a successful response. —For example, the order status isn’t updated in the database until a response that indicates success is received. If necessary, the caller can retry the operation.
- The following are the asynchronous callout limits as of the time of this writing. These limits may change in the future, and you should always check the official documentation.
|Maximum number of parallel Apex callouts in a single continuation
|Maximum number of chained Apex callouts
|Maximum timeout for a single continuation
|Maximum Visualforce controller-state size
|Maximum HTTP response size
|Maximum HTTP POST form size—the size of all keys and values in the form
|Maximum number of keys in the HTTP POST form 3
- The timeout that’s specified in the auto-generated web service stub and in the HttpRequest objects is ignored. Only this timeout limit is enforced for a continuation.
- When the continuation is executed, the Visualforce controller is serialized. When the continuation is completed, the controller is deserialized and the callback is invoked. Use the Apex transient modifier to designate a variable that is not to be serialized. The framework uses only serialized members when it resumes. The controller-state size limit is separate from the view state limit. See Differences between Continuation Controller State and Visualforce View State.
- This limit is for HTTP POST forms with the following content type headers: content-type=’application/x-www-form-urlencoded’ and content-type=’multipart/form-data’
Making Multiple Callouts
You can make up to three asynchronous callouts in a single continuation. Add these callout requests to the same continuation by using the addHttpRequest method of the Continuation class. The callouts run in parallel and suspend the Visualforce request. Only after all callouts are returned by the external service does the Visualforce process resume.
Chaining Asynchronous Callouts
If the order of the callouts matters, or when a callout is conditional on the response of another callout, you can chain callout requests. Chaining callouts means that the next callout is made only after the response of the previous callout returns. For instance, you can chain a callout to get warranty extension information after the warranty service response indicates that the warranty expired. You can chain up to three callouts.
To learn more about integration patterns and practices, see Integration Patterns and Practices.
To learn more about asynchronous processing, see the Trailhead module on Asynchronous Apex.
Additional great resource, see Avoiding Apex Speeding Tickets .
About the Author
Karishma is a Architect Director in Advisory Services specializing in enterprise-wide systems integration of Salesforce technology across industries such as Insurance, Telecom, Utilities, Financial Services, Supply Chain, Biotech and Public Sector. She has 10+ years of international experience in the areas of Enterprise Application Integration (EAI), Technical Architecture, Application Development and Deployment. She is also a Salesforce Certified Technical Architect and is passionate about solving complex problems through simple solutions.