Working with on Salesforce.com platform, part of my job ends up revolving around finding unique ways to solve coding limitations. Salesforce.com has a myriad of limits in place around code to prevent a single organization from hogging resources in the multitenant environment. In theory, this has actually made my code quite a bit more efficient when applying some of the principles to other platforms, but it also makes you design your applications quite a bit differently than you might have done in the past.
One of the limitations of the platform only allows one level of asynchronous activity: the initial invocation of code, and the ability to create a select number of future methods that will execute in a few minutes asynchronously. Unfortunately, those asynchronous calls can’t chain together additional asynchronous calls. One of the implementations I recently did required that extra level of asynchronous activity via the following process:
- Receive a webhook with information about an event that just occurred.
- Query the API to see if the event had been completed. If not, wait a few minutes and try again.
- Retrieve a list of all the users tied to the completed event.
It turns out that the only way I could find to get around this limit was to execute step 1, persist the event information in a table (in this case a custom object), and then set up a scheduled job that ran every few minutes querying the API for event completion. Another unfortunate limitation came about here: an HTTP callout via a scheduled job already counts as an asychronous call.
At this point, I needed a way to make the additional calls. What I ended up deciding to do was to fire off a request to another server (not Salesforce.com) that told it to make a subsequent request back to an endpoint with some custom parameters that would then invoke the final step.
[Note: While writing this post, I came to the realization that I simply could have updated the completed status of the event record in the table I used for step 2 in order to invoke a new set of conditional actions via the next running of the scheduled job. Doh. At least it forced me to learn some interesting stuff below.]
In order to do this, I needed to quickly spin up a single endpoint application that would take in a few parameters (namely the URL I wanted to redirect back to and some additional parameters about the event), parse them, and make a server-side HTTP request right back (didn’t want to mess with CORS). I’ve had a lot of experience with Java in the past using URLConnection to create requests in main classes for testing, but hadn’t dealt with spinning up a simple application in a long time, so I decided to try out a quick Ruby on Rails application hosted on Heroku. [Note: this is probably a great use case for Sinatra, but I haven’t tried it out yet and wanted to knock this out quick.]
I’ve done some Ruby on Rails programming in the past, primarily fun little side projects designed more towards B2C web applications that I never get around to finishing, but apparently I had never needed to write code for making HTTP requests out of Rails because I had no idea how (apparently I’ve been spoiled by API gems). After doing some quick research, I realized that the out of the box Ruby library Net::HTTP seemed a bit more wordy than I wanted. Instead, I ended up leveraging HTTParty, a lightweight gem that abstracted what I needed to do (make a single request) into one line of code:
response = HTTParty.get(‘http://myurl.com?param1=abc’)
I was pleasantly surprised at how simple this use case ended up being. Coding something up like this in Apex (or Java) takes significantly more lines of code out of the box (similar to how I imagine Net::HTTP works), and it might even be worthwhile to set up a quick class in Apex to replicate this kind of logic in the future. Additionally, the Rails + Heroku solution couldn’t have taken more than 15 minutes to get live. Hooray for the cloud.