PowerApps Automation – Run Once!

PowerApps Automation – Run Once!

Creating Model-Driven Apps (MDA) is very efficient for me. I can design forms and views for my Dataverse tables in minutes. Furthermore, adding these tables to my app takes only seconds. Plus, I can add since a while Power Fx commands to my App in the Command Bar. However, executing Power Automate flows can sometimes be tricky. That’s why I’m sharing my Automation Run Once solution today, which helps prevent Power Automate flows from running twice.

Recently, I noticed that my flows sometimes run twice. Moreover, I was able to reproduce this issue in my Model-Driven App. It was quite a challenge and a real problem for me to solve the issue.

You wonder why? Let me explain this in other words. I usually use Power Automate Flow for the implementation of my business logic. This means, a Power Automate Flow is triggered by a condition and executes afterwards its logic. This logic can be, for example, an update to the data, the start of an approval process, or something else. In my case I send notifications. But this happened twice to my surprise.

This means, I had to solve the problem for my app.

My Example Scenario

Before we delve into my solution, I will draft to you, my scenario. As introduced, the big picture is I’m using a model driven app and trigger a Power Automate flow that sends a notification message.

In detail, I’m using in my App a command bar button Start Execution to invoke the flow run by patching the record. Here is a picture that outlines my scenario:

You see also, my flow triggered from Dataverse. Here I’m using the trigger When a row is added, modified or deleted:

This trigger allows me to start my flow when a row is added, modified or deleted in my Microsoft Dataverse table. In detail, my flow reacts to the changed information and send a notification message to a Microsoft Teams chat.

Friends from Power Atelier also pointed out, I can configure parameters Select columns and Filter rows together to limit the execution only to the selected and filtered columns:

This worked better but not 100%. Therefore, I started to investigate another solution.

Defining the Run Once Automation Process

My problem happens during Power Automate Flow execution. This means I have to solve the problem directly in my Power Automate Flows. My concept is simple. I will create a function Start Execution that writes a record in a table Execution History. Furthermore, I will parameterize this function with unique information of the workflow run and the execution that should happen once.

A unique key at the table Execution History will prevent any duplicate execution with the same parameters. For this I will generate a name from the given function arguments. This means, any key violation of the name will raise an error that cancels the execution.

My function needs arguments. Here I must provide information about workflow execution. Therefore, I include details about the unique execution itself. Additionally, I will specify if I want to run the flow once.

Table Execution History

My Execution History table tracks the execution information for the critical Power Automate flows in my application. Here I’m using Workflow Id, Workflow Run, and Workflow Name to store the workflow specific information from expression workflow(). Also, Run Once and Execution Id will help to identify and limit the workflow execution. Lastly, I’m adding the column Workflow Run URL. This column allows users to navigate directly to the flow run in Power Automate.

Here are my created columns:

My table is almost ready to store my Power Automate Flow executions. As the last part, I’m making sure that my table allows only one Run Once record at the same time. Therefore, I’m adding a unique key and selecting the name field:

Later I will set the Name of my record based on the execution arguments.

Extending Table Demo Execution Record

Here in my triggering table Execution Demo Record, I add only 3 new columns. The columns are Execution Enabled, Execution Id, and Execution Run Once. Execution Enabled is set to Yes when a flow execution should start. The Execution Id is like a correlation id and ensures uniqueness. Finally, the Execution Run Once is used in this demo allow changing the run once behavior from user interface.

My added columns are here:

Start Execution as Unbound Action

Since a while there is a new preview feature in my Dataverse. Yes, I can now create functions in Microsoft Dataverse. An amazing thing is that Functions use Power Fx to execute a specific set of commands within Dataverse that run server-side. Behind the scenes these Functions are like the good old Unbound Actions.

Therefore, I’m creating an Automation Function in my solution:

Now I will give my new function the name Start Execution and define the 3 input parameters. Furthermore, I add my code to the function:

Firstly, I’m adding the parameter workflowDetails (String). This will help me to transfer the JSON information from expression workflow() from Power Automate Flow into my function. As second parameter, I’m using executionId (String). This will be the self-defined id of the current execution. Finally, I’m setting up the parameter runOnce (Boolean). This is because I want to use this function also to track my workflow execution based on the Execution Id.

Now I must define my function code. First, I extract and decode in my function the workflow information from the parameter workflowDetails. Then I’m preventing a double execution in case parameter runOnce is true by raising an error. This happens when already another execution was tracked in my table.

Next, I’m adding the current execution as a new record to my table Execution Histories. The important fact is that I calculate my record name that must be unique based on the runOnce parameter. If runOnce is true, the combination of executionId and Power Automate flow workflow_id can appear only once in my table. This constraint will be ensured by my created table Execution Histories.

Here is my created Power Fx code:

// Decode the workflow() JSON
With({wf: ParseJSON(workflowDetails)},
// Extract workflow information
With({
    workflow_id:     Text(wf.tags.xrmWorkflowId),
    workflow_name:   Text(wf.tags.flowDisplayName),
    workflow_run_id: Text(wf.run.name),
    environment_id:  Text(wf.tags.environmentName)},
// Search an existing record with the same workflow and execution id
With({record: LookUp(mme2k_executionhistory As item, 
                     item.mme2k_workflowid = workflow_id
                  && item.mme2k_executionid = executionId)
},

// Raise an error when the record already exist.
If(runOnce && ! IsBlank(record), Error("Execution already tracked"));

// Track the execution in a new record
Collect('Execution Histories', 
    {
        'Name':            If(runOnce, 
                              $"{executionId}-{workflow_id}", 
                              $"{executionId}-{workflow_id}-{GUID()}"
                           ),
        'Workflow Id':     workflow_id,
        'Workflow Name':   workflow_name,
        'Workflow Run':    workflow_run_id,
        'Execution Id':    executionId,
        'Run Once':        If(runOnce, 
                              'Run Once (Execution Histories)'.Yes, 
                              'Run Once (Execution Histories)'.No),
        'Workflow Run URL': $"https://make.powerautomate.com/manage/environments/{environment_id}/flows/{workflow_id}/runs/{workflow_run_id}"
    });

)));

After creating my new function, I have these components in my solution:

Using Start Execution in Power Automate

Now my function is ready, and I can use it in my Power Automate Flow. First, I’m creating a scope action with the name Run Once. I do this, because I can copy that scope including the content easily to another flow. Next, I’m adding a Dataverse Unbound Action to my flow. Here, I’m selecting the correct name of my created function (mme2k_StartExecution). My parameters appear afterwards. Here I’m using the workflow() expression to pass all workflow details to my function. I also configure executionId and runOnce parameter based on the values of the triggering record:

Finally, I have added a Terminate action to my flow. In addition, I have configured parameter run after with option has failed:

This allows me to cancel my Power Automate Flow, when my Start Execution action raises an error.

Testing Run Once Automation

Initially, I told you that I noticed some of my Power Automate flows were executed twice. It took me a while, but I found the trigger of my problem. A Power Fx button caused my problem when it modified my record to start a Power Automate flow. Digging deeper into the scenario, it discovered to me that this happens exactly when my record was unsaved.

Let’s set up this scenario and add a Power Fx button to my Model Driven App.

Power Fx Button in Model Driven App

First, I start editing the command bar of my table Execution Demo Records directly from the Model Driven App editor:

Next, I’m selecting the Main form:

I am doing this for the first time in my solution. Therefore, the editor asks me to create a component library for Power Fx buttons. I acknowledge and continue:

Next, I’m adding my new command Start Execution:

Furthermore, I’m using this Power Fx code for the Visible property of my command:

Self.Selected.Item.'Execution Enabled' = 'Execution Enabled (Execution Demo Records)'.No

This ensures that my command is not present when I have already started an execution. In detail, this avoids an unintended double modification from my command.

My command itself uses this Power Fx code to modify the record and start my execution.

Patch('Execution Demo Records', Self.Selected.Item, {
    'Execution Enabled': 'Execution Enabled (Execution Demo Records)'.Yes, 
    'Execution Id': GUID()
});
Notify("Execution triggered...", NotificationType.Success, 20000);

You see that I always generate a new Execution ID by using the GUID() command. This allows me to execute the command multiple times for my test scenario.

Houston, we have a Problem!

Let’s test the scenario first without my prepared run once logic. I’m creating a new record and enter as name test. After, I changed the name to test 1 without saving.

So far so good. My current record in my App is unsaved. Now, I’m executing my Start Execution command:

Remember, my Start Execution command will Patch(..) my record by setting Execution Enabled to Yes and generating a new unique Execution Id.

Let’s have a look at my Power Automate Flow. Yes, this has directly caused a double execution:

You see also, the start time is nearly the same. This means, disabling the execution directly after the flow started was useless:

BTW, it would not help to run only one instance of the flow, because the trigger was raised twice. This is because the filter expression will not filter out the modification.

A closer look to the data shows us. There is no difference between the data of the triggering records:

The left side is the record from the first flow run. The right side shows the same information, but from the second flow run. This is bad.

As a result, my flow ran twice and generated 2 times an entry in the Notes table. After refreshing my record, I’m seeing this:

There are 2 notes with the same Execution Id. Finally, this is bad, and I must solve this.

Problem Solved with Run Once Automation!

Second round! I have set up another test record. The record is again Unsaved before I’m clicking on Start Execution. But here I’m using my prepared Execution Run Once parameter with the value Yes:

Again, the Power Automated flow is triggered twice. I see directly the success of my modification. Now only one of the flow runs was executed and the second is canceled:

In the first flow run, my Start Execution action allowed the start, and the Termination was skipped:

In contrast, the second flow run was Canceled because my Start Execution action raised an error:

Cool, my “Run Once” functionality works as expected!

Run History

Another advantage from my Run Once pattern is that I can now track all my flow executions based on the Execution Id in a list:

Furthermore, I can directly navigate from my list to the flow run by using the Workflow Run URL. As result I see my executed Power Automated flow:

This allows me in operations to investigate my flow execution. This becomes more important when I have a chain of Power Automated flows that are executed in a sequence.

Summary

Let me wrap up my blog post for you. I faced initially the problem that sometimes my Power Automated flows were executed twice. I noticed this behavior, because I found duplicate notification messages in my original scenario. The problem itself was caused by my Power Automate flow that reacted on a modification of my Dataverse record from a Model Driven App. Here I did not use the trigger parameters well to receive only one on-modified event.

To solve my problem, I developed the Run Once pattern which works well for my scenario. In detail, I created another Dataverse table that tracks my Power Automate executions. In addition, I have added a Power Fx function that I can call with the action Execute Unbound Action from my flow. Here, the function is using my workflow run parameters to add a new row to this table. In case of I parameterized Run Once, my function set up the name of the record as defined, and the unique key of my table ensures that this record can only be added once. As result, I cancel the flow when my function (unbound action) raises an error.

That pattern works so good for me that I have seen the potential for other solutions. In detail, I’m using this approach for lots of my Power Automate flows which are triggered per example by a Status Reason change. With this, I’m enforcing that my critical Power Flows are executed only once in my application. Furthermore, I get secondly a history of my flow executions. I’m using this a lot to analyze my application because I see also the correlation of my flows due to my Execution Id.

Share
Comments are closed.