2

I feel like there should be a straightforward answer here, but I'm coming up short...

Trigger event: Account lookup field on Lead(s)/Contact(s) are updated OR a particular Account field is updated

Action: Update specified field on Lead(s)/Contact(s) based on the related Account's field value.

Desired behavior: Asynchronous updates so that the initial DML on Leads/Contacts/Accounts is not affected. (Ideally ~1 min)

Thought process:

  • Process Builder: Minimum 1 hr wait
  • PB + Flow: Flow runs in user context, will cause permissions exceptions
  • PB + Flow + Invocable Apex: Cloud Flow Designer cannot assign collection variables to Apex (see here)

Question(s):

  1. Process Builder (immediate action) + Invocable Apex + Queueable: I'm not 100% clear on how PB handles bulk updates. I've noticed in the past that PB will create multiple queued items from a single bulk transaction, so my assumption was that it's separate transactions for each record. Say, for example, I mass update the Account field on 200 Leads, if that satisfies a PB criteria node, is that considered one transaction or 200? If the former, then I'll hit the Queueable limit of 50 per transaction. If the latter, I won't.
  2. If it does consider it one transaction, I assume the recommended way to proceed would be through Triggers. But, if there's something better, I'd love to know.

Thanks in advance!

  • Do you have an overriding need to build the solution starting from Process Builder, or is a 100% Apex solution feasible? – David Reed Feb 23 '18 at 14:54
  • @DavidReed Overriding, no. But I’ve got a small team and ideally my non-Dev admins would be able to maintain the trigger logic. It’s not the end of the world to use a Trigger but Dev time is at a higher premium. – Mike Feb 23 '18 at 14:56
  • 2
    Understood; I ask because if the concern is performance and transaction control, that suggests trigger + Queueable as optimal. That said, I'll defer to someone who can speak directly to your questions about Process Builder performance characteristics. – David Reed Feb 23 '18 at 14:58
  • @DavidReed UPDATE: Process Builder is apparently the worst of both worlds. It considers it all one transaction, but doesn't treat a bulk update as a collection. So, each individual record is passed into the class separately & attempts to enqueue hundreds of jobs - hitting the queueable limit. Trigger appears to be the only way to go. – Mike Feb 24 '18 at 16:36
2

Unfortunately, I believe you'll need a trigger, at least as far as kicking off the process. If you're feeling adventurous, you should be able to call the flow from Apex Code, so at least the main logic is controllable.

trigger on Account (after insert, after update) {
  Account[] records = new Account[0];
  for(Account record: Trigger.new) {
    // Figure out what this means to you
    if(meetsCriteria(record)) { 
      records.add(record);
    }
  }
  if(!records.isEmpty()) {
    System.enqueueJob(FlowCaller(records));
  }
}

public class FlowCaller implements Queueable {
  Account[] records;
  public FlowCaller(Account[] records) {
    this.records = records;
  }
  public void execute(QueueableContext context) {
    Map<String, Object> params = new Map<String, Object> {
      'accounts' => records // accounts is flow sobject collection
    }; 
    Flow.interview.DoSomethingCool theFlow = 
      new Flow.Interview.DoSomethingCool(params);
    theFlow.start();
  }
}

Note that Queueable is your best choice here, but it won't be a minute delay, it'll be something more like 0-15 seconds (on average), depending on system load. It will be in a separate transaction, though (asynchronously), which is your goal.

You could even have two flows; the first could be invoked in your trigger to determine the matching criteria (it would return a list of records to evaluate), and the second to do the logic of actually updating records.

  • Thanks. According to the article I linked to in the OP: "The Cloud Flow Designer doesn’t support mapping an Apex method’s input or output parameters to an sObject collection variable." Is your suggestion somehow getting around this? The other issue is that Flows run in user context and the user who triggers the action might not have edit rights to all Leads & Contacts. In any case, it's not so much the business logic that I'd want admin-editable, but rather the trigger logic. Do you have any thoughts re: PB behavior when a bulk action invokes a Flow which enqueues jobs? – Mike Feb 23 '18 at 16:57
  • @Mike We're calling the flow from Apex, not calling Apex from the flow. Totally different scenario, and it should work, IIRC. Invoking PB to do bulk flows will probably hit limits. And as I said, you could call a flow to control trigger logic, too. – sfdcfox Feb 23 '18 at 17:10
  • Beyond the complexity, I have a feeling it wouldn't work since the document says Apex method outputs cannot be mapped to an sObject collection variable in a Flow. I think what I'll test is calling Invocable directly from PB (avoiding the Cloud Flow Designer) with a bulk update and see if it limits the queueables to 50. If so, I'll move it to a Trigger. – Mike Feb 23 '18 at 17:49
  • @Mike You can't map from PB to a collection, but you can map from Apex to a flow: Map<String, Object> params = new Map<String, Object> { 'accounts' => new Account[] { new Account(), new Account() } }; Flow.Interview.FlowDemo myFlow = new Flow.Interview.FlowDemo(params); myFlow.start(); – sfdcfox Feb 23 '18 at 17:54
  • Gotcha, thanks. I'm curious how this would get around the user context problem since I would not be able to pass the collection back to Apex for DML. – Mike Feb 23 '18 at 18:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.