Apex – How Does Bulkification Work for Records in an Invocable Action in a Flow?

apexinvocable-methodvisual-workflow

If I have an invocable method that is bulkified to handle multiple records updated in a single transaction, what is the most efficient way to write the Flow that calls it?

My initial Flow design lets the Flow's record-by-record interview send each single updated record that enters the Flow to the invocable method (as List< sObject >). My dev instincts tell me to send all the updated records to the invocable as a collection (List<List< sObject >>) just like Trigger.new would do, but is that necessary? Wouldn't Flow still run a distinct interview for each record and end up sending the same collection of all updated records repeatedly?

It's working as-is but I can see it using a lot of resources for each additional record I add, so I'm hoping that there's a Flow bulkification design I can apply.

Best Answer

If you have an invocable method that runs with certain input, it should be coded as if you are passing the items from a transaction context into it. That is, if your flow runs on an object creation or update, it is the equivalent of creating an Apex method that handles the context of that transaction - the list of records or inputs from the flow.

So, if you have a method with a signature of (List<SObject> records), it means that your invocable method will be invoked once for a batch of records in a transaction context. I'm saying this because even for triggers the records are split into batches of 200 records. In this example, if you are performing some DML in an object that triggers a flow that calls this Apex action, if you define that records input variable in the Flow Builder UI as the $Record variable from the flow, it means that when your flow runs, it will run that method for all the records of that object in that transaction.

As an example: if you have a flow that runs this Apex action whenever an Account is created, it means that if you create five Account records that list passed onto your method will contain the five Account records.

The same principle applies to signatures using custom Apex subclasses. It is common to have an action defined as a class and then have a subclass to represent its inputs, like so:

public class MyAction {
    public static void run(List<Input> inputs) {
        // ... do something with inputs
    }

    public class Input {
        @InvocableVariable(label='Name')
        public String name;
    }
}

In this scenario, imagine you are passing the $Record.Name (the Account's name) as the value for the action's input in the flow. If you have five Account records in the transaction, then the action will receive a list of all of your records' Name values in that name attribute of the custom element. Subclasses like this are common for situations where you need to process multiple parameters.