Saturday, 7 February 2015

Lightning Process Builder and Invocable Methods

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:

Screen Shot 2015 02 07 at 11 51 44

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):

Screen Shot 2015 02 07 at 11 56 17

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:

Screen Shot 2015 02 07 at 11 57 34

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:

Screen Shot 2015 02 07 at 12 06 13

and updating the record to validated automatically deletes these tasks:

Screen Shot 2015 02 07 at 12 06 23

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.

12 comments:

  1. Hi Bob,

    Does 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.

    ReplyDelete
    Replies
    1. Hi,

      I 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
      }

      Delete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Why does the invocablemethod "AccountValidated" taking list of account Ids?
    Shouldn't it take just a single account Id? As everytime an account record is validated it goes through process builder.

    ReplyDelete
    Replies
    1. Got the answer!! That invocablemethods accept only list of elements :)

      Delete
  4. Hi Bob,

    Can 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




    ReplyDelete
  5. Can't we call @invocable method from apex class or controller?
    Please let me know.

    ReplyDelete
  6. Hi Bob,

    If 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

    ReplyDelete
    Replies
    1. Invocable method will work in community also.
      You 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

      Delete
  7. Hi Bob,

    I 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??

    ReplyDelete
  8. Hi,
    Can I have more than 1 InvocableMethods in my class?

    ReplyDelete