If you create flows for your organisation, or for clients on projects, you’ve no doubt improved your skills over the years. This might mean you started including steps in the flow to notify you of any failures. Or you might have just come in to a project with tens or even hundreds of flows and it might not be realistic to go through and add new actions to each to check for errors. So how can you find out when flows fail without going through and editing them all? This was my own recent mini challenge to solve. I wanted to know when flows might be failing and send an email to my self so I could dig in and find out. This post will show how you can create a notification for failed flow runs in power automate.
I searched for a way to do this for a while, but was lead back to adding in a notification step to each flow which just wasn’t practical with so many flows as part of the project I was on. I also wanted a summary of the flow runs that failed rather than one each time. I also found things using PowerShell and the Dataverse API. I wanted something a bit simpler if possible. Then I found this link from Vaibhav Ghorpade sharing a new preview feature from Microsoft. using the Cloud flow run history in Dataverse, I could then create a flow to find any failed runs from the previous day and send an email.
First things first, go to the Power Platform Admin Centre, then Environment Settings and find the Cloud flow run history in Dataverse. You can store the flow run logs for 28 days, 14 days or 7 days, or disable in completely. The length of time you want to store them I guess depends on what you want to do with them. If you are just sending an email and have no other need for the data to be in Dataverse, 7 days is probably good. There is no setting here to determine which runs get stored, so keep in mind it will store all of them (Failed, Succeeded, Cancelled etc).
Once you turn it on, you would be able to go to the Flow Runs table and see the rows of data being stored.
Now let’s build the flow. This will be a scheduled cloud flow that I will run at 10 AM each day.
The first action will be to initialize a variable that needs to be an Array. This will be used throughout the flow to populate information about the flow runs that failed and put them in to a nice table for the email.
The next step is a list rows action from the Dataverse connector using the Flow Runs table. You don’t need to select any specific columns but I only wanted specific things, so I’ve set it to these ones:
duration,endtime,errorcode,errormessage,flowrunid,name,starttime,status,triggertype,_workflow_value,_ownerid_value,workflowid,ownerid
For the filtering, I only wanted those that ran yesterday and the status is Failed. I’m sorting them in descending order of when they were created but you can sort by the name or anything else if you choose. This really depends on the order in which you wish to see them in the email.
(Microsoft.Dynamics.CRM.Yesterday(PropertyName="createdon") and status eq 'Failed')
Now that we’ve searched for the failed flows, we only need to continue if we have more than one failed flow. To do this, add a condition and then add an expression to check the length or number of records found. If you have left the default name of List rows in the step above, your expression will be the same as in the screenshot below. However, if you’ve renamed it, just add that but with the words separated by underscores like you see in the text below. Select the is greater than option from the middle drop down, then add zero in the last box. We want the number of rows found to be greater than zero to continue.
length(body('Failed_Flow_Runs_From_Yesterday')?['value'])
The no path of your condition branch will be empty. If the number of rows found is not greater than zero, no email needs sending. Now add in an Apply to each step in the yes branch, and use the value output from the list rows step to get started.
First we are going to build a link to the flow run that failed using a Compose step. This will mean we can add a direct link so that the person receiving the email can just click on it to see the information and figure out why it failed. The inputs for the Compose are using a bit of HTML to create a hyperlink, then creating the full path using the GUID for the environment (workflow()[‘tags’][‘environmentname’]). The workflowid is used to get the GUID for the flow, then the name is used to get the GUID for the specific flow run. We can then use the workflow name (name of the flow) as the thing to display in the email for the hyperlink.
<a href="https://make.powerautomate.com/environments/@{workflow()['tags']['environmentName']}/flows/@{items('For_Each_Flow_Run')?['workflowid']}/runs/@{items('For_Each_Flow_Run')?['name']}">@{items('For_Each_Flow_Run')?['workflow/name']}</a>
You only need this if you want the name of the person that owns the flow to show in the email. Otherwise you can ignore this step. I tried getting it from the list rows step but it always showed up empty. So here I am using a Get a row by ID step for the Users table, then using the Owner value from the List rows step and selecting the fullname column only.
Now we add the details for each flow run that failed and using an Append to array variable action we start adding in the details for our table of flow runs. You can include whatever you like, but for mine I am using the Outputs of the Compose step where I created a hyperlink, then showing the start date/time of the flow run, the duration, then the name of the owner of the flow. Notice that the Duration needs an expression so it shows in hours/mins/seconds or ms depending on how long it is. You don’t have to do this, but if you don’t it will just be a long string of numbers in milliseconds only,
{ "Flow": "@{outputs('Link_To_Flow')}", "Date": "@{formatDateTime(items('For_Each_Flow_Run')?['starttime'], 'dd-MM-yyyy hh:mm tt')}", "Duration": "@{if(less(items('For_Each_Flow_Run')?['duration'], 1000), concat(items('For_Each_Flow_Run')?['duration'], ' ms'), formatDateTime(addSeconds('1970-01-01T00:00:00Z', div(items('For_Each_Flow_Run')?['duration'], 1000)), 'HH:mm:ss') ) }", "Owner": "@{outputs('Get_a_row_by_ID')?['body/fullname']}" }
Now you are done with the Apply to each so you can minimise that and add in a step outside of the Apply to each but still in your yes branch from the condition earlier. Here we need the Create HTML table action. Use your Flow Runs variable as the From value and keep the Columns as Automatic, we’ve already determined those.
As with a few other items, this isn’t needed but can be used to make the table look a bit prettier by adding in a Compose step, then setting some CSS to style the table, and including the Output from the Create HTML table step above at the end. If you want to know more and get an example to start with, check out this post from my friend Ryan Maclean on Power Automate HTML Table Styling.
Now this next step is necessary to clean up the HTML from the step where we created a nice link to the flow run. It gets a little broken when we use the Create HTML table step, but that’s OK, we can fix it. And thanks to Strategy 365 as I found a post of theirs that provided the expression. Where you see Compose below, that should be whatever you named the step above where you added your CSS. If you didn’t add that step, it should be whatever you named the Create HTML table step. This will fix specific characters in the link HTML.
replace(replace(replace(outputs('Compose'),'<','<'),'>','>'),'"','"')
Next we will add an action from the Power Platform for Admins connector. Click on the Get Environment as Admin. Note that the only reason I am using this step is so that I can get the name of the environment to use in my email so I know where the failed flows came from. This is really useful if you work with an organisation with multiple environments.
Use this expression to get the environment name.
workflow()?['tags']?['environmentName']
Finally, use whatever step you want for sending out your email. I’ve got the standard send an email notification action but you could of course use Outlook, SendGrid or whatever works for your organisation. You can set up the email however you choose, but I am adding in the date of when the failed flows are from, and showing the name of the environment in the subject.
Failed Flows From @{formatDateTime(addDays(utcNow(), -1), 'dd-MM-yyyy')} - @{outputs('Get_Environment_as_Admin')?['body/properties/displayName']}
Then in the email body, I am showing the number of the flows that failed in the specific environment, then using the output from the final compose step where we fixed the broken URLs. For the number of flows, I want it to be accurate English, so if there was only 1 flow that failed, I am showing “There is 1 flow“, and if there is more than one, I am showing “There are X flows”.
@{if(equals(length(body('Failed_Flow_Runs_From_Yesterday')?['value']), 1), 'There is 1 flow run that failed yesterday', concat('There are ', length(body('Failed_Flow_Runs_From_Yesterday')?['value']), ' flow runs that failed yesterday') ) } in the @{outputs('Get_Environment_as_Admin')?['body/properties/displayName']} environment. @{outputs('Fix_URLs')}
Now once the flow runs, if you have any failed flow runs from the previous day you should get a nice little
Original Post http://meganvwalker.com/notification-for-failed-flow-runs-in-power-automate/