Note: Apex can now be called from workflows as
using the Process Builder.
Here is a simple hack to call Apex classes from workflow rules.
Problem: Salesforce has a magnificently declarative environment for creating point-and-click applications and workflows, but one area that gets particularly gnarly is executing business rules in response to changes in state.
Given a problem like "When Opportunity stage equals 'Closed-Won', send the order to the back office system for processing", the Business Analyst has a good idea of "when" the business process should be executed. The Developer knows "how" the process should be executed.
The result is often the development of a trigger that includes both the "when" and "how" logic merged into a single class. The trigger ultimately ends up containing code to detect state changes; a task otherwise best left to workflow rule conditions.
Future enhancements to the business rules require the BA to submit a change request to the Developer, impairing the overall agility of the system.
(Some discussions of detecting record state in trigger can be found here
The Solution: Calling Apex From Outbound Messages
Empower the System Administrator/BA to create workflow rules that call Apex classes in response to declarative conditions.
Create a workflow rule with an outbound message action that calls a message handler (hosted on Heroku), that in turn calls back to a Salesforce REST resource.
Components of the Outbound Message:
- The endpoint URL is hosted on Heroku. The outbound message handler receives the message and issues a callback to Salesforce using the path provided after the root URL.
- Pass the session ID to the endpoint (Note: the 'User to send as' must have permissions to call and invoke the Apex REST web service)
- Pass only the Id of object meeting the workflow condition. This gets passed back to the REST service as an "oid" parameter (object id).
Download the Heroku outbound message handler from Github (link).
git clone https://github.com/cubiccompass/sfdc-om-workflow
Build the solution and deploy to Heroku.
git commit -am "Initial commit"
heroku apps:create omhandler
git push heroku master
Create a workflow rule with an outbound message action that calls the Heroku hosted endpoint.
Create a Salesforce REST resource for handling the callback.
To see the workflow in action, view the Heroku web service logs while updating records in Salesforce that trigger the workflow rule.
heroku logs -tail
In the real world, I'm evolving this design pattern to include an IWorkflowTask interface to clearly distinguish which business objects handle workflow actions. The execute() method takes a WorkflowContext object that includes more details from the outbound message.
Daisy Chaining Workflows:
It's important that workflow tasks record or modify some state after executing a task in order to allow for triggering follow-up workflow actions.
For example, an OrderProcessor workflow task might update an Order__c status field to "Processed". This allows System Administrators to create follow-up workflow rules/actions, such as sending out emails.
Security: Use HTTPS/SSL endpoints to ensure session information is not subject to man in the middle attacks.
Idempotence: Salesforce does not guarantee that each outbound message will be sent only once (although it's mostly consistent with 1:1 messaging). REST resources should be developed to handle the rare instance where a message might be received twice. In the use case above, the code should be designed to defend against submitting the same order twice; possibly by checking a 'Processed' flag on a record before submitting to a back-office system.
Workflow tasks are called asynchronously, so there's a decent amount of processing and execution freedom using this pattern.