<span id="hs_cos_wrapper_name" class="hs_cos_wrapper hs_cos_wrapper_meta_field hs_cos_wrapper_type_text" style="" data-hs-cos-general-type="meta_field" data-hs-cos-type="text" >Using asynchronous actions in a Flow</span>

Using asynchronous actions in a Flow

This post is part of a technical series to help Salesforce Admins automate business processes using Flow. We're very excited to feature a new guest author, Andy Adkins! Andy is a Salesforce expert, especially when it comes to Flow.

Introduced in the Winter ‘22 release, Salesforce added another Flow ability: Asynchronous actions.  This post discusses how to use this new ability in Flows, using an example of a Flow to remove permissions and licenses when a Salesforce User is deactivated.

Salesforce Flow has gradually been adding more capability that used to only be possible with Apex Code.   Previous updates have replicated the functionality of automation “before trigger” which are changes that happen BEFORE a triggering event is committed (labeled in Flow as “Fast Field Updates”), and “after trigger” updates which happen AFTER a triggering event is committed (labeled in Flow as “Actions and Related Records). New to the Flow ‘neighborhood’ is the checkbox at the bottom of the options screen to include a “Run Asychonously” path.

What are the benefits of asynchronous actions? One benefit is that if a process takes a noticeable amount of time to run, you can “delay” the additional process work until after the change, rather than the end user having to wait for completion. Instead, the change is saved, and then the process runs in the background. 

Another benefit (and the reason I chose Asynchronous for this use case) is that if an Asynchronous Flow fails, it does not prevent the triggering action from completing. It allows the change, and will alert the appropriate admin of a failure, and then keep trying to run in the back ground every few minutes. If this happens you can view (or delete) any pending repeats in the “Time-Based Workflow” section of Setup.

This is why connecting to external systems is mentioned by name in the option on the screen above. If there is an issue connecting to an external system, then Salesforce will keep trying to connect.

Use Case - Automatic Cleanup for User Deactivation

This example will use a record-triggered Flow to handle a tedious process -“cleaning up” when we deactivate a User. This will remove deactivated users from their managed package assignments, permission sets, and more. Since we have an automation from an external system that deactivates users immediately when employment ends, I did not want to risk the deactivation action being stopped. I also want to get an email of the results, for tracking.

Defining the Flow Start Elements

Step 1 is to create a Record-Triggered Flow based on the User object, with these options in the Start action:

  • Trigger when “A record is updated”
  • Entry Conditions are when the Field “IsActive” Equals  {$GlobalConstant.False}
  • When to Run the Flow  is set to “Only when a record is updated to meet the condition requirements.
  • Because removing permissions involves a related record, I need to choose the Optimize option for “Actions and Related Records”
  • Lastly, select the “Run Asynchronously” option

Create the Record Variable and Initial Assignment Action

Text Variable for UserID, UserFullName, and for ChangeLog. The Name and ChangeLog variables will be used in my email notification.

We will only need the ID and Name items, so create an Assignment element to update the variables from the record triggering the Flow. Using variables prevents the same record from being accessed over and over in the same Flow.

I can also start my ChangeLog variable with the name variable. “Changes for {!UserFullName} -”

When linking the Start element to the Assignment element, make sure and select the Asynchronous option:

Create a Loop for Deactivation Items

For removing the managed package licenses, there is a native object that links Users to managed packages: “User Package License”. I want to remove any of these objects that are tied to the triggering user.  

Create a Get Records action to get all of the records that match my UserID variable:


This will store any matching records in a collection. To delete each item in the collection, we need a loop!

This Loop item will go through the Collection variable created in previous step.

Then a Delete Item action within the Loop to remove the “User Package License” records for the user that has been deactivated.

Optional, but recommended, is to add an Assignment item in the loop to log the changes, which can be included in the email result. Use the ChangeLog variable and choose “Add” as the operator to add text. You can mix the variables and plain text in your email body, such as:

“License- {!RemoveLicense.PackageLicense.NamespacePrefix} Removed | “

“ID - {!RemoveLicense.Id} Id || “

Connect all the items in the loop. 


This takes care of the core action needed, and can be a good place to debug the Flow so far, to see how it works.

New call-to-action
Notifications For External License Managers

This is optional, but a Decision Element within the loop can be used to notify other people in your organization about any specific changes.  For example, we have an integration that another team administers, so I added a decision in the Package License loop to notify that team when a license is deactivated.   


Decision can use the {!RemoveLicense.PackageLicense.NamespacePrefix} field for matches.

Email can include the UserFullName variable.

Create Other Loop Elements for More Cleanup   

Although this covers the basics of how this flow can be created using an Asynchronous trigger to clean up assignments for a deactivated user, the same building blocks of this flow can be expanded to include other loops to remove other assignments as well.   In my case, I added these elements:

A loop to remove assigned Permission Set Assignments that match the UserID

Object: Permission Set Assignment

(Note: Include a Decision to exclude items where IsOwnedByProfile is True, because those are Profiles and will generate an error.   {!ForEachPermissionSet.PermissionSet.IsOwnedByProfile}) 



A loop to remove each Permission Set License Assignment

Object:  “Permission Set License Assignment”


A loop to remove each Public Group Assignment

Object: Group Member



When All Is Complete, Email the Results

At the end of the Flow, add a Send Email action to send the results that have been added throught the flow to the ChangeLog variable to yourself, or any email addresses.

This completes the Flow build. Hopefully this project has been helpful, not only learning to use an asynchronous action, but also to learn about the metadata related to user permissions and licensing to automatically clean up data when someone is deactivated in Salesforce.

Related Posts

Do you use Flow to automate lead distribution? 

Gradient Works is an ultra-flexible lead distribution automation solution for Salesforce. And it's not just for leads - we can automate the assignment of any object. Plus, integrations with Slack, Outreach, Salesloft, Google Calendar, Microsoft 365 and more...

Learn more with a customized demo and free trial