Skip to main content

Asynchronous Apex webservice callout - Continuation pattern



In my last two posts, we went through a basic example of consuming an external web service in Salesforce to generate a stub class and then using that stub class to call the webservice from a visualforce page controller.
In the above example, our callout was synchronous. The user as well as our code (system resources) are going to wait for the webservice to reply and our code to process the response prior to be able to do anything else. If the external webservice responds within 1-2 seconds, no harm done. This should be fine.

However there are chances you will encounter webservices in business scenarios that will take longer to respond. This may be because they have to do a significant amount of work prior to responding back to Salesforce. Maybe they process huge number of transactions and during peak loads, their response is slower. All possible scenarios can exist. Now Salesforce being a multi-tenant environment needs to safeguard its customers like you and me from such eventualities which may slow down the entire system. So they have governor limits.  The governor limit of particular interest for us is -

This is taken from Salesforce's site - Transaction governor limits.

If I read it correctly, it means at any given point of time, if there are more than 10 concurrent synchronous requests taking more than 5 seconds, you will run into weird runtime errors. 

Imagine 20 of your callcenter users clicking the Convert button at a given point of time. Also if your external webservice is unusually slow today due to heavy traffic at its end or some other issue at its end, you will start seeing weird errors in Salesforce. Hmm...we dont want that definitely.

So a good practice in such scenarios is to use asynchronous integration if possible. I say if possible as it is not a one size fits all solution.

Give good consideration on how you will pass inputs to the asynchronous call and how the results coming back will be processed. Remember the asynchronous callout runs in a different thread and has no access to your original context. It cannot pass back values directly. So you will need to think through how the response is processed and presented back to the user. Will the user lose anything if the response comes back later and he has proceeded to the next step in the business process already?

Lets say, we found asynchronous works fine for us. (Well our usecase here is temperature conversion on a visualforce page, whats to lose :) ). How do you implement it. Two ways I know of -
1. Using the @Future annotation to create Future methods. I will explain these in the next post.
2. Using Asynchronous apex callout or Continuation pattern.

We will change our previous code from this post to use Continuation.

This post Apex Continuations on the developer.salesforce.com website explains Continuation pattern very well.

As explained, in this pattern, using a system class Continuation, we create a Continuation instance. To this continuation we provide our callout inputs and a callback method. The Continuation object executes our apex callout for us in a separate thread. Once it has the results, it calls the callback method with the results. Now we get control back in our main thread with the results. We can process the results and present it to the user.

The overall experience for the user appears synchronous. Behind the scene, we executed the callout asynchronously and avoided possible governor limits. Internally Salesforce puts the main thread to sleep during the callout (handled in a different thread) and then recreates the main thread after the response is received.

Very important point from Salesforce on this pattern - "The main consumer target is a VF page being used by lots of users that is integrating, real-time, to a heavyweight external system." So use this pattern only if you confirm to the earlier statement.

Now to our code changes. We are reusing the Visualforce page from our previous post - Integrating Salesforce with SOAP webservice - Apex callout part 2 . It already had the "Convert Continuation" button which was calling a method - callContinuationMethod in our Controller. I will show the code for it below and explain it. 

But first, lets go to the post - Integrating Salesforce with SOAP webservice - Apex callout where we created our stub classes. There was a class "AsyncWWWw3schoolsComWebService" that got created. This is our Continuation pattern stub.

The method beginFahrenheitToCelcsius takes a continuation as input along with the fahrenheit string value. It calls the webservice and returns an instance of another class. This elementfuture class has methods to retrieve the result of the webservice callout.

Now lets put it to use in our controller - 

Note: I have created an extra method callContinuationMethod. In hindsight, that is not required, you can avoid and use getCelciusContinuation directly.

To explain the code - 
  • the callContinuationMethod is called by the visualforce page. It is not doing much other than calling the getCelciusContinuation method.
  • getCelciusContinuation method is our key method here. 
    • It is creating a Continuation object instance. It sets a timeout of 60 seconds (you can change it based on your situation). 
    • It then sets the callback method as "processResponse".  
    • It invokes the Async webservice stub with the continuation as one of the inputs. 
    • It returns the Continuation object at the end of its execution.
  • processResponse method is called back by the thread which actually executes the callout. The response from the callout is taken and passed back to the Visualforce page. In this case, it is set to a class instance property.
  • Important note on the Visualforce page. The commandButton that invokes the continuation has a reRender attribute value set. This is important. We want to rerender the pageBlock which shows the output property when the button's execution is done.
 Now execute the Convert Continuation button on your visualforce page and see the results. The behavior looks same as synchronous right?! How do you verify what happened? Lets look at our Debug logs -


As you can see above based on our debug statements, the Continuation gets called and the actual callout is not in our main thread. It executes in a different thread and later calls our callback method.

Thats the Continuation pattern! Remember it is useful only if a visualforce page is involved. In other scenarios, its usage may not be appropriate. If you wish to make your callout asynchronous and actually dont have a user UI to worry about, then it may be better to just use a future (@future) method instead. I will cover that in my next post. 


 


 


Comments

  1. why does the continuation pattern not work if VF page/UI is not used. In a batch program, processResponse never executes? Any ideas?

    ReplyDelete
  2. Thats correct, this pattern works only if a VF page is orchestrating the pattern. I have not seen any documentation explaining this further. THe main thread which gets the call back has to be a VF page controller.

    ReplyDelete
  3. Very concise and useful post on apex web service callout.

    Thanks for sharing Salesforce Online Training and salesforce training hyderabad

    ReplyDelete

Post a Comment

Popular posts from this blog

Workaround to bypass Salesforce SSO

One of the best practices for implementing Single Sign On for your Salesforce org is always ensure there is a way your System administrator can login via the standard login page side-stepping the SSO configuration.  Reason for this is if ever something goes wrong with your Idp provider's service and the SSO authentication responses are not coming as expected, all your users are unable to login. That is, if you have setup your My domain to prevent logins via standard Salesforce login urls (login.salesforce.com). This includes the System administrator as well. Only if your system administrator can somehow login, then he or she can disable the SSO settings for your domain and allow login via the normal login page as a temporary measure. What do you do in such a situation? Well Salesforce has built a workaround for this which is not well documented anywhere (probably for a good reason :) ). I found out about it from a colleague at work. If your my domain url is - https://Com

Salesforce Big Objects - Key learnings

I remember reading about Salesforce Big Objects before they became available and thought maybe it is an option to backup data present in regular objects. That is, instead of taking a backup via an ETL tool or data loader, maybe this will be an option to backup the data in the Force.com platform itself. Now that it is GA and I am reading more about it, i think the use cases for this are more varied. Some use cases I can think of are –  Archival of key data objects within the platform: You may want to use this option if you dont use any other means to backup key data. Also this may be an attractive option for non-large enterprise customers who dont themselves invest on large data warehouses or data lakes in their enterprise architecture. Ex: customer history (if present in tasks and activities) will become huge over years but this is useful information for reporting & customer analysis. Store key information which is large volume in quantity and also high volume in transa

DBAmp for Salesforce - salesforce integration for SQL Server DBAs

Recently i got the opportunity to explore a tool called DBAmp for integration with Salesforce. I found it to be a very useful tool which will help with any data manipulation requirements in Salesforce. Following are my learnings from the exercise. Hope it helps any of you who may need to work with this tool -  DBAmp is a SQL Server package that can be used to integrate with Salesforce. The site where this software is available is - http://www.forceamp.com/ Overview: It essentially installs on top of an existing SQL Server database and provides an OLE DB connector that can be used to connect to Salesforce. Behind the scenes, it executes API calls against Salesforce for any SQL server command it receives. Thus we can create a connection in SQL server to Salesforce org and pull data into tables in the database just as if we are querying against Salesforce tables directly. Use cases for DBAmap + Salesforce: Many use cases exist for using this tool against Salesforce. Pr