A framework for using the promise pattern in Apex
Writing instructors tell you to answer the five W’s: who, what, where, when and why. Mine even instructed me to answer them in that particular order. But today we’re talking about asynchronous code execution and promises. That means it might be easier to write this post a bit out-of-order:
I’ve always understood the hardest thing in computer science to be naming things. Followed immediately by cache invalidation and asynchronous execution, of course. Writing, debugging and maintaining asynchronous (and/or multi-threaded) code is hard.
The joke, in fact, has always been ‘hard, asynchronous is, debug to.’
Promises get their name because they represent the promise of an eventual value. A Promise is a state machine with three states: Pending, Resolved and Error. (These states may have different names depending on the implementation.)
A promise starts its life in Pending status. As the code completes, it either succeeds and becomes Resolved, or fails and ends up in Error status. Promises solve the ‘when’ problem by introducing a method, .then(). This attaches the passed concluding code to the initial method. Promises do this by adding to, and executing methods from a stack. Every invocation of .then() adds to the stack. Executing the promise causes the stack’s methods to run in order.
The state machine, combined with a stack make Promises easy to describe (in English). (I, the developer) promise the system that this method will return some data. When it does, ‘then’ do this other work I’ve described.
One of the stellar features of Promises is their ability to return not only data, but a new Promise. This allows you to chain promises together into processes. For example, a developer might need to pull some data from a third party API. However, before she can access the data, she has to authenticate. In practice means making a callout to authenticate and retrieve an oAuth token. Token in hand, a second call retrieves the data. With Promises this can described as a single process:
Why Promises? (another? promise library for Apex?)
All this talk about promises has been empty theory until recently. With the release of Winter ’15, Salesforce gave us QueueableApex. QueueablexApex is the interface that enables the implementation of Promises in Apex. Last year at Dreamforce I gave a talk on the Promise pattern and how to implement it in Apex. Unfortunately, none of the example code had that beautifully simple syntax using .then(). After my talk, Chuck Jonas, (Developer extraordinaire) wrote a promises implementation called Apex-Q. Chuck’s library is amazing, but I wanted something a bit simpler. Apex-Q includes two types of Promises. One that facilitates HTTP Callouts, and one that doesn’t. The trade-off needed to make all Promises HTTP callout safe, however, is pretty minimal. Namely, the data passed between promises must be JSON serializable. Today I’m happy to release Promise an alternative implementation for Promises in Apex.
How (do I use it)?
With the Promise framework, you’ll create classes that represent each ‘step’ of your promise chain. These classes simply implement the Promise.promiseStep interface and look like this:
The promiseStep interface requires only the resolve method. The resolve method must return a SerializableData object. Each resolve method accepts the output of the previous step. The output of the previous step is dependency injected into the next resolve method.
Once you’ve implemented each of your promiseSteps, you can execute a promise chain like this:
Note: while this example has two demo steps, if your process had, say 5 steps, you’d simply add 3 more .then(new someClass()) calls.
Under the covers, the .then() method populates a List of promises. The execute() framework method pops the first promise step off the list and executes it. If there are other steps on the list, it enqueues the next step by calling an @future annotated method. If the execution of a step throws an error, the framework invokes the error handler. The framework’s .error() method allows you to specify the error handling class. Finally, the .done() handler is always run! The done handler, is a great place for notifications and any other wrap-up work you need to do.
You can find Promise here: https://codefriar.github.io/promise/. You can install it in your sandbox or production orgs using the deploy button at the bottom of the readme. Promise includes a test class. Additionally, Promise includes some example classes demonstrating use of the framework. The tests provide nearly 100% coverage. However, they rely on the included example classes. They are too functional for my taste. For now, please note that deleting the example classes from your org will cause the tests to fail.
If you’ve ever written code to make several sequential HTTP callouts… If you’ve wondered how to ensure one batch process completes before the next starts… Promise can help. Promise is for Apex developers who develop, debug and maintain asynchronous code. Promise is not only for doing integration work with external services. In fact, anytime you need to attach code execution to the completion of other code, Promise can help!