Lightning Process Builder and Invocable Methods
Overview
The new Lightning Process Builder (which I’ve take to calling workflow on steroids) goes GA with the Spring 15 release, introducing a greater number of declarative actions that can be taken when a record matches specified criteria:
- Create a record (not just tasks!)
- Update any related record (not just immediate parent)
- Launch a headless flow
- Quick action
- Send an email
- Post to chatter
- Submit record for approval
If the above actions don’t cater for your particular requirements, you have the final and killer action:
- Execute Apex method
This allows you to execute custom Apex code, and once you are in Apex-land you can do pretty much anything you need to.
@InvocableMethod Annotation
In order to allow an Apex method to be executed as a Process Builder action, you need to use the @InvocableMethod annotation.
Example
Here’s an example of using an invocable annotation that I built for the BrightGen Spring 15 Salesforce Release Webinar around account validation. There are a couple of processes involved.
Process 1 - Create Validation Tasks
When an account is created that is unvalidated, send emails to key users asking them to validate the account:
Process 2 - Clean up Validation Tasks
Once the account is changed to validated, delete the task records - this involves invoking an Apex method as there is no action to delete a record (although hopefully this is something that will be introduced in a future release):
Defining an apex action is straightforward - simply choose the Action Type of ‘Apex’, give the action a name and then choose from the available classes that contain methods annotated with @InvocableMethod:
Apex Method
The TaskUtils task contains a single method that is passed the id(s) of the accounts whose validation tasks are to be deleted, locates the validation tasks based on their name and deletes them:
public class TasksUtils { @InvocableMethod public static void AccountValidated(List<Id> accountIds) { List<Task> tasks=[select id from Task where whatId in :accountIds and Subject = 'Validate Account']; delete tasks; } }
Creating an account that is unvalidated automatically adds 2 tasks:
and updating the record to validated automatically deletes these tasks:
Comparison With Trigger
Looking again at the Apex method, there no code aside from that to locate the tasks and delete them:
public static void AccountValidated(List<Id> accountIds) { List<Task> tasks=[select id from Task where whatId in :accountIds and Subject = 'Validate Account']; delete tasks; }
To achieve the same thing with a trigger, I’d need to embed the business logic that determines whether the Validated field for the trigger accounts has been changed to true, then continue on with the code to locate the tasks and delete them.
This is less than ideal, as :
- business logic encapsulated in triggers is resistant to change. To alter the logic I need to update the trigger code in a sandbox and then deploy to production.
- to allow an administrator to disable the trigger on demand I’d need to use something like a custom setting and add code to retrieve and check the value of the setting before continuing with the trigger code.
- Its a little less testable, as to test the trigger I have to insert a record, and there may be other trigger logic in place that affects the record, leading to more of an integration than unit test. With well-written triggers that delegate to helper classes this isn’t much of a downside, but testing the simple invocable method fits the definition of unit testing perfectly.
So would there be any reason to continue to use triggers once Spring 15 is live? The answer is yes, for much the same reason that you might have used triggers to in place of workflow in the past - order of execution. It’s still not possible (as far as I’ve been able to find out anyway!) to define the order in which processes for the same object will execute, whereas in triggers its straightforward to define the order that processing will take place as long as you adhere to the one trigger per object and action pattern.
Hi Bob,
ReplyDeleteDoes it support the API call out ?
If I have a trigger on an Object which is communicating with external system using future method.
I have implement the same with Process builder and it was giving "You have uncommitted work pending. Please commit or rollback before calling out".
I double check the code and there was no DML before the Callout.
Could you please share your view ?
Any help on this would be appreciated.
Hi,
DeleteI had the same problem, the workaround is to use a future method:
@InvocableMethod
public static void myMethod(List recordIds){
myMethodFuture(recordIds);
}
@future (callout=true)
public static void myMethodFuture(List recordIds){
//Callout are allowed here
}
This comment has been removed by the author.
ReplyDeleteWhy does the invocablemethod "AccountValidated" taking list of account Ids?
ReplyDeleteShouldn't it take just a single account Id? As everytime an account record is validated it goes through process builder.
Got the answer!! That invocablemethods accept only list of elements :)
DeleteHi Bob,
ReplyDeleteCan you please help me on the below scenario.
I want to make some fields as required on knowledge article types.But as per salesforce limitation we can't make required fields so i have approach through process builder and restricted in the code to make the field as required.
when i create a record or update with null value in the required field,it is allowing to update that required field in the code .when i debug i can see the "error field is required" in the code which i make required field in the code.
Can you please share ur thoughts on this
Can't we call @invocable method from apex class or controller?
ReplyDeletePlease let me know.
Thank you
ReplyDeleteHi Bob,
ReplyDeleteIf i am calling invocable in internal salesforce using apex code then it's working fine.
But when i am using in Community then i'm getting an error in console - 503, Service Not Available
So it invocable method will work in community ?
Thanks,
Rajendra
Invocable method will work in community also.
DeleteYou have to pass SitePrefix when you are calling them as Ajax Request.
It's bug of skuid Custom apex action that are not pass SitePrefix during invocable method callout.
Thanks,
Rajendra
Hi Bob,
ReplyDeleteI created new process builder and I am calling apex if it matches the criteria. Invocation method is getting executed but parameters is null.
Please let me know what's wrong??
Hi,
ReplyDeleteCan I have more than 1 InvocableMethods in my class?
No,
DeleteWe can have only one InvocableMethods in one class.
In My case, A B C. B Juction object
ReplyDeleteWhenever A obj is created it will create B object. Then after it will created C and update the C obj value in B obejct look up field. Its possible? How