Flow Triggers (Before-Save and After-Save)

Other Pages on Flow Triggers

spring '21 updates in progress

Before-Save Flows - much rejoicing was had when the Spring ‘20 release notes first came out… but are they all they are cracked up to be… let’s investigate. But first, have you seen a Before-Save Flow demo video (apart from mine) that does anything more than updating one or two fields… let’s get real here, in the real world we need do to soooo much more.

After-Save Flows are also released in Summer '20. Winter 21 release had a few new features but still not enough to move Process Builders to Flows. After-Save Flows release notes and other Flow enhancement release notes.

In Spring ‘21 I think we are finally there! I will update this post with tips and tricks as I migrate all my complex calculations to Flow from Process builder. (Let’s start with https://tddprojects.atlassian.net/wiki/spaces/SF/pages/1642987525/Percentage+Fields+in+Flows weirdness).

What do I want Flows and Process Builder to do

  • Display Validation Rules correctly. Geezus. Who ever thought the current way Flows fail with a validation rule is acceptable? Still not good in Spring '21.

  • Be easily able to update data for duplicate management without having to write a trigger. Yep!

  • More clarification or less confusion over the whole “One Process Builder per Object” rule and “don’t mix Flow, Process Builder, Workflows and Triggers” rule. I don’t necessarily subscribe to these rule, but that needs a whole other post and what I learn here might change my thoughts. (disclaimer: I don’t work in large enterprise orgs, so I’m only talking about small to medium sized orgs with small to medium sized complexities). This is going to be way more valid for After-Save Flows also. There is some documentation on this topic now in the Architect Decision Guides, and I have started writing about this in https://tddprojects.atlassian.net/wiki/spaces/SF/pages/1777336343/Flow+Triggers+Naming+and+Grouping .

  • Maybe getting away from DLRS… I love DLRS but as Andy is no longer able to support it to the extent that it needs, I’m worried about it’s longevity. And sometimes it’s flaky and sometimes it causes issues (again this probably needs a whole other post). I’m still going to use DLRS.

  • The “Always” updates - the fields that are like formulas but the formula is > 5000 character compile size so it needs to be an update. This is the whole basis for my https://tddprojects.atlassian.net/wiki/spaces/SF/pages/739082247/Multiple+ways+to+run+Flows+for+multiple+records talk at Japan Dreamin. Now, the caveat to this is building formulas in Flows SUCKS! even worse than building formulas in Process Builder! This is NOT addressed yet as at Spring '21.

  • Make it easy to do a criteria like “If all of these fields are not entered then don’t allow the stage to be changed”. When you can’t fit all of your criteria into a formula this becomes a pain to manage because you have to manage both setting the validation field AND clearing the validation field when the record is subsequently edited to NOT match the validation. I need to do another post on this.

Things we are still going to need Process Builder or Flow for

  • After Update queries (obvs)

  • Chatter Posts, Notifications and Email Alerts

  • Platform Events

  • Subflows!!! (Not Possible with After-Save Flows!)

  • Workflows on Long Text or Rich Text Areas

  • Creating new related records or updating related records

  • Invocable Actions

Things I will still only use Workflow for…

  • Time-based Workflow

    • The implementation of time based updates in Flows is terrible. If it has less features and is less reliable and is less customisation than existing functionality why would I use it? It is just bad.

  • Email Alerts, if there are a lot of emails being automated

    • Who’s stupid idea was it to have seemingly orphaned email alerts because you can’t see that they are used in Process Builders? And it’s not even in the new Where is it Used functionality.

    • Email Alerts can now use Lightning Email Templates in Spring '21 but they are still orphaned in the UI!

  • Where a complex formula is used more than once

    • Nope, Invocable Process Builders are just a waste of time, and see above re formulas in Flows… I sometimes just want to stick with what I know works. (May be less of an issue with the ability to run Apex in Flows, and the release of the Automation Components).

  • Long Text and Rich Text Fields

    • You STILL cannot build record triggered flows that are triggered based on the contents of a long text or rich text field. Eg I have a field named Instructions and another field named InstructionsExcerpt that is used to validate if Instructions is filled in. InstructionsExcerpt is updated every time the Instructions is Edited and IF it is not null. This will stay as a workflow. You need to have an after-save flow that is triggered ALWAYS, then include a decision in that Flow. I’m not sure it’s worth it unless you have another Always After Save Flow.

    • Foiled again! Dammit!

  • Just because

    • Why would I rebuild anything that is already fully functioning in Workflows… (nice to see this reiterated by Jen Lee in the Architect blog post)

A small sidebar…

I have a client with very complex currency calculations that of course are more than the 5000 compile size limit. We had a major structural change to the object so it was best to create a new object to refactor the database (to more closely mirror the external system we are integrating with). This was just 12 months ago so Process Builders are well entrenched and are definitely the way things are “meant” to be done.

All the formulas were basically the same. So this is a great opportunity to move everything to the recommended way of doing things right…

Well, what a nightmare. The record was so slow to save (no delay in saving the same formulas in workflow rules) that I had to severely restrict when the fields were updated, which has caused issues with people not believing the data they see… very understandable.

So now I have to either rebuild everything in flow triggers, or get right to it and code all these highly complex formulas (that do change based on government legislation changes for example. And yes, we did just have a huge change in government legislation due to Covid).

Questions before I delve in

  • So we have a process that needs to update some values, create some records, notify another user, add a chatter post to the record and send an email. So we are going to have the updates in the Before-Save Flows then have the rest of the bits in After-Save Flows… Isn’t this breaking the rules? Well maybe not, since Before-Save flows have their own place in the Order Of Execution before everything so it’s almost like we are removing the load of those updates from the Process Builders… but is it still going to be slow because of all the other things? The updates would not be a heavy load on the whole transaction in that scenario. (But we can do things in Process Builder to mitigate this now, like using the 0 hours wait time to almost do a “@Future” method but in Process Builder or Flow).

  • Think of the classic scenario why they told us that Process Builders were sooo much better than Workflow Rules - where you have different field values based on different criteria. So I have exactly this scenario. I have 6 fields that can be different values based on one field that has 7 different options - basically it's a picklist with a list of presets and you choose that and it goes and sets all these other fields with the right values that make an external system function. Am I going to have to do all those combinations in one formula in Flow? No, decisions in Before Save Flow should do the trick now.

  • Does “Where is this Used” work for Assignment Elements in Flow? (I don’t think so).

  • Are Flow Triggers bulkified? I don’t see how they are when they run once for every single record. Check the Architect Decision Guides on this…

Starting to Work

My first foray into Before-Save Flows was in a pre-release scratch org where I made a quick video about changing from a regular flow to a Before-Save Flow.

Over the next few releases I tried again, but just had to give up. I am now starting fresh in Spring '21.

Issues with Before-Save Flows

  • You can’t Debug Record triggered Flows!!!!

    • Make sure when you are debugging that you have turned off ALL other Flows, Process Builders, Workflows etc that may cause things to not work right.

    • In Spring ‘21 there is now a debug link from the email alert on failed Flows… it’s good. But debugging directly would be better.

Add an Assignment element named Error as the last element in the flow. Make an error happen in this Assignment item (eg set RecordID to a blank value) and turn on the Debug Log. This saved me big time!

  • The full value of a record is in the Debug Log… now this would be the same if you added all field value variables but it is a bit of an eye opener and makes you definitely think about the data security of your debug logs - especially if you are using things like the https://tddprojects.atlassian.net/wiki/spaces/SF/pages/789217319/Debugging+in+SFDX options.

  • Wow. Having to select the $Record with a mouse (I can’t find a keyboard shortcut to quickly expand it and start typing the field name), is such a PITA.

    • Of course this is an issue with ALL flows, and is one of the things that makes me hate flows, and makes me hate building formulas in flows,

  • You can’t use CMDT in Formulas… it’s so bad I would say don’t bother doing anything with CMDT… leave them in Process Builder.

    • So there is a work-around but it requires completely rethinking your CMDT - ensure the CMDT has enough fields to be able to select the right record with a Get Records that returns only one record. Then you can get the fields from that CMDT record.

Example

Case({!ThisRecord.MyFieldHourOrDay__c},
"H",$CustomMetadata.MyMD__mdt.Scenario1HourID.ExID__c, "D",$CustomMetadata.MyMD__mdt.Scenario2DayID.ExID__c,
0),

It’s OK if you’ve got one of these, you can do that in a formula, but when you have 15 combinations to look through to choose the right MDT record, the formula gets too big.

  • Before-Save Flows don’t trigger on Deletion (I had not gotten to the point of considering this yet, but one commenter raised this as an issue). After-Save Flows do though.

  • When setting defaults in Before-Save Flows don’t do what I did and overwrite what users have already entered. Ensure you do something like:

1 IF(ISBLANK(TEXT({!$Record.YourField__c})),"Default Value,TEXT({!$Record.YourField__c}))

Good Things

Tips

  • Naming Convention: See https://tddprojects.atlassian.net/wiki/spaces/SF/pages/1777336343/Flow+Triggers+Naming+and+Grouping for tips on Naming your Flows

  • Ensure you don’t accidentally assign a value that will ALWAYS set the value to that and will never allow the value to be set to anything else. Eg as shown in the Release Demo Video for Before-Save Flows!

  • Create a Checkbox on your record (eg Disable Auto Update for Before-Save Flows), default False… Set this as the first Condition in your Flow… just in case you need a way to opt out.

  • Are there fields that always should be entered? If so, put these into a Before-Save Flow for Create only, rather than running this each time it’s updated (except if it changes of course - this is more for default values).

  • You can maybe turn off field required-ness on create for some fields that you can now set through these flows. (or event better, requiredness may be able to be set through https://tddprojects.atlassian.net/wiki/spaces/SF/pages/965312517/Dynamic+Forms+and+Dynamic+Actions)

  • If you are doing a Before Create and Before Update in the same Flow then ensure you use a Decision Element before you do a Get Records on a related Object, so your flow does not fail when that lookup field is not filled in (or when the value is cleared in an Update).

  • Decide what happens after the record gets to a certain status - eg Closed Won Opp, or Closed Case. Do these flows run then?

    • Duplicate the Final Assignment Element, stick a Decision before it for the Status / Stage and only set those values that MUST be changed after that Status / Stage.

    • Or use a Lock Record Flow Action on a regular Flow to lock the record (hmm, if Before-Save runs before even Before triggers, does the regular record lock feature even prevent Before-Save updates from happening? And how does Lock Record work if Flows are run in System Context - all this needs to be tested, do not take my word for it).

  • Turn a Before-Save Flow conditionally into a Before Update or Before Create by checking for the existence of the $Record.Id. Rather than maintaining two flows… maybe… check if it slows things down.

  • Check your formulas for what happens when there is a null value. The resulting field will be Null. Do you want it to be null or 0.

My Scenario

For the Contract Fee I have a Percentage Field and a Base Rate. If the Percentage Field is not filled in I want the Contract Fee to be null. But If I enter a 0% Percentage then I DO want the Contract Fee to say $0.

In formulas this is as simple as checking the Treat Blank Fields as Blank box (or otherwise), but you have to handle it yourself in Flows.

When to use After-Save

Note: The Architect Decision Guides say DO NOT use After-Save Flows for single record field updates… this is not practical at all.

  • When one of the fields has a value set that is based on a formula containing a field that is set by DLRS or Trigger. After Save Flows happen after Triggers.

Gotchas

  • You CAN NOT use formulas that include values from any other field set by the Before-Save record. Think of the field as being null always and every time you edit the record this field value is going to be set again. Note, I need to check this now that I’ve worked out you CAN use formulas in Before-Save flows. Oh wow, it looks like it works!!! See https://tddprojects.atlassian.net/wiki/spaces/SF/pages/1643085893/Formulas+in+Flow+Triggers for more details on this

In my scenario above. I enter the Base Rate - it is never set in my Assignments in my Flow. I always set my Contract Fee based on the Percentage and the Base Rate.

But what if I have another formula that I want to calculate Contract Total that is added as the Base Rate plus the Contract Fee.

If the formula for fContractFee is $Record.BaseRate__c * $Record.Percentage__c

The formula for fContractTotal can not be fContractFee + $Record.BaseRate__c

It would have to be ($Record.BaseRate__c * $Record.Percentage__c) + $Record.BaseRate__c

(I’ve excluded all the null checks for clarity).

Then I have another formula that spells out the Contract Total in words to display on the Contract documents. So I would have to put the full formula calculation for every part of the formula that requires any part of the value. (For example see all these stupid formulas just for adding the dollar signs). Nope.

That’s all fine for simple formulas but for complex formulas that is a need to go into After-Save Flows.

  • You use $Record_Prior to find the prior value of a field.

    • But you could come into strife - test it really well.

    • Think of the differences between setting a default and what the user intended to set.

My Scenario

On my Contract I have a field for the Signatory. The Default Signatory is set as a field on the Account. If I am creating a new Contract I always want the Default. But if they change the Signatory away from the Default, then I do NOT want this Before-Save Flow to override their choice.

If the Contract is Activated, and the Default Signatory changes on the Account, and I happen to update any field on a Contract after that, then I do NOT want the Signatory to change to the new Default Signatory from the Account, I want it to always remain as the Signatory it was set as.

So, why not do this in a Before-Save Flow only for Create… yep that is fine. But what if my Account changes before the Contract is Activated (eg the Contract needs to be for the Parent Account which is the National Office, rather than the Branch Office. If I change the Account, I ALWAYS want to set the Default Signatory again.

So this is probably where I would revert to doing a Before-Save Flow on Create, then an regular Process Builder on Is Changed… it gets too hard in a Before-Save Flow on Create and Update.

Suggestions on working through changing existing Process Builders

Not sure if any of these are valid… just trying to work through them.

  • Decide what needs to go into Before-Save and After-Save and what needs to absolutely stay in Process Builder. See Below as to what needs to stay in Process Builder.

  • Deactivate all your Process Builders, Workflow Rules, (triggers if needed) first, so you can see what is being set by this Flow only.

  • Decide on ALL the Decision elements you need and add them to your canvas

  • Ensure you always do a decision to check for Blank Values IF the field is not required on Create.

  • Add a decision element for checking if $Record.Id is blank.

  • If there are only a few fields that need to be updated based on a Status, then do formulas instead of a decision element. Eg If two fields should only be updated if the Status is Draft and their values should remain the same in all other circumstances then build a formula like IF({!fIsDraft} = true, {!Account.MyField__c}, {!$Record.MyField__c}).

  • Save regularly so you know if the formulas or $Record assignments are incorrect (why oh why oh why can’t it evaluate formulas as you click OK, or have another button to evaluate the formula?).

  • Add your final Assignment at the bottom of the Canvas and don’t tie it up to the rest until you have finished everything else.

  • The Final Assignment should only assign $Record elements, not other Variables.

  • Create Formulas with the exact name of the API name of the field that is to be updated with a f in front eg fContractFee (No, I do NOT have underscores in my API names).

  • Think about your STOP criteria. These Assignments should only assign Variables, never Assigning $Record

  • Build all your formulas before you start adding them to your Assignment.

    • Copy your Formulas over from Process Builder into a text editor and replace the syntax in bulk.

    • Eg replace “[Account].” with “{!$Record.” and

  • As you build your formulas, remove them from a copy of your Process Builder.

After-Save Flows

Good Things

  • You can Delete. With great power comes great responsibility though!

  • Conditional Chatter Posts!!!! Way more easier than Process Builder!

  • Submit for Approval!

Issues with After-Save Flows

  • No Sub Flows

  • Runs even if nothing changes on the record (does triggers do this?)

Questions for After-Save Flows

  • When to use Created or Created and Updated as separate Flows?

    • Without Subflows it’s difficult.

  • How will they work bulkified when the flow only runs on one record at a time.

  • Are we still only meant to do one Flow per Object? As per above questions.

  • How do all the new Flows Permissions affect all this?

One Flow Per Object - Reasons Against

  • No Sub Flows

  • No Bulkification

  • Can have flows with different permissions levels

  • Objects with different record types may be used for very different things. Maybe have the first decision element being a STOP decision.

Things you still will NOT be able to use Flow Triggers for

  • Pause or Wait in Flow - yes there is definitely valid reasons to use this in headless flows - eg using the 0 minutes wait trick to do things in another transaction.

    • Workaround may be to use Invocable Apex

  • Where I call a Flow - eg assigning a Topic to a record, I have that in a generic Flow - I would have to make that an Invocable Apex instead.

  • Quip Actions (I haven’t used them but I can’t see them in Flows).

More to be added here!