Environment Variable caching in Power Automate
In this blog post, we will talk about Environment Variable caching in Power Automate, what the problem is with it and how to work around it.
I have attached both a managed and unmanaged solution containing the complete flow to this post. You can find the link furthure down at the bottom of this page.
This blog post is obsolete. There was a new feature released in July 2022 which pushed changes to an Environment Variable to every flow using the environment variable in question. This makes my manual handling unnecessary.
Read more
Background
As of writing this blog post (2022-02-22) Power Automate Flows do cache environment variables. This applies to Flows using the out of the box Environment Variable integration, basically use an EnvVar directly from the list of available EnvVars.
If you happen to change the value of an environment variable it will not be used by any Power Automate Flow until you turn the flow off and on again.
This behaviour has cost me already quite a lot of time and hair.
Structure Environment Variables
Before we go into detail regarding the solution I would take a moment to explain how Environment Variables are structured. This is needed to understand what my solution will query from Dataverse.
An Environment Variable can basically consist of two parts.
- Environment Variable Definition
- Environment Variable Value
The definition contains all the needed information to define a Environment variable.
- Display Name
- Schema Name
- Description
- Data Type
- Default Value
The Value (I tend to call it local value) only contains a environment specific value which should override the default value.
Microsofts idea behind it is that the definition is part of a solution, where as the value should not be. When the solution is then moved to the downstream environment one can present a local value. This will (in the OOB integration) override the default value if present. One of both (either default value or local value) has to be present at any time, otherwise the maker portal will show a small error on the top of the page.
Solution
The solution I tend to use to tackle this problem is to create a child flow. This flow would take the Environment Variable SchemaName as an input and respond with the correct value. I would then call the child flow within my flows whenever I need the value of an Environment Variable.
You could also install/create a custom API or Action to do the job and call that from within your flow. One example of such an custom API is the GetEnvironmentVariable from David Rivard (LinkedIn & Twitter). Creating one needs a developer and installing third party APIs might not be allowed by your IT Department. That’s when the flow solution I mentioned comes into the picture.
In either way our solution has to follow the idea described earlier. When a local value is present this should be responded with if not we will take the default value.
Flow
Let’s get the actually flow build.
Create & Trigger
First we create a new instant flow using a Manuall trigger as well as choosing a good name.
In the trigger we add “EnvVarName” as an input of type text.
Load EnvVar definitions
As the fist step we add a List rows action from the Dataverse connector.
In the Table we select “Envrionment Variable Definitions”, Row count should be 1 and in Fetch Xml Query we add the following fetch XML.
<fetch top="1"> <entity name="environmentvariabledefinition"> <attribute name="defaultvalue" /> <attribute name="type" /> <filter type="or"> <condition attribute="displayname" operator="eq" value="@{triggerBody()['text']}" /> <condition attribute="schemaname" operator="eq" value="@{triggerBody()['text']}" /> </filter> <link-entity name="environmentvariablevalue" from="environmentvariabledefinitionid" to="environmentvariabledefinitionid" link-type="outer" alias="value"> <attribute name="value" /> </link-entity> </entity> </fetch>
This will load the first environment variable definition which has the input text either as displayname or schemaname. It will also get the environment variable value if present.
I wasn’t able to reproduce the same behaviour just with OData, since one can’t have a outer link type. In that case the result was empty when no EnvVar value was present. Therefore we are using the fetchxml instead.
Init variable
This step isn’t necessary but makes the “extension”functionalities easier. We initialize a variable called “RespondValue”.
It should contain the environment variable value if present and the default value in other case. To achieve that we use the following powerFx expression as the Value.
if(empty(first(outputs('List_EnvVarDefinition')?['body/value'])?['value.value']), first(outputs('List_EnvVarDefinition')?['body/value'])?['defaultvalue'], first(outputs('List_EnvVarDefinition')?['body/value'])?['value.value'])
Respond with Value
Last step would be to respond with the content of the variable. To do that we add a step “Respond to a PowerApp or flow” from the Power Apps connector.
The output should be called “EnvVarValue”, of type text and be the variable we just created.
Add more functionality
Now that we have the basic flow we could add more functionality. I would like to explain two more features I tend to implement.
Secret
When the Environment Variable is of type Secret the value has to be loaded in a different way. In that case Microsoft provided an unbound Action one could call to get the secret value. The Action would get the value from the configured Azure Key Vault.
What we have to do is to check the Environment Variable Type and call the action when it is a Secret.
To do that we add a Condition step where we take the type of the first value of the list row response and compare it to the ID of the Secret Type (which is 100000005). With the following expression you will get the id of the type of the first row in the list rows step.
first(outputs('List_EnvVarDefinition')?['body/value'])['type']
In the true path we will add a step of type “Perform an unbound action” of the Dataverse connector. In the field “Action Name” we select “RetrieveEnvironmentVariableSecretValue”, which is a Action provided by Microsoft. As the Input we send in the input from our trigger.
On the same step we would like to secure the output since we already know it’s some kind of secret. To do that we select the three dots and click on Settings.
On the next screen we make sure the second flip switch is true.
Lastsly we have to set the just received value to the variable we created earlier.
Casting
An Environment Variable could be of one of different data types.
The current solution will always have the value it responds with as type String/Text. What you might want to have is the value casted to the actual type.
I am not aware how the type “Data source” should be casted. Please feel free to let me know if you do.
Since JSON also just is a different form of Text we don’t have to cast that. Neither do we have to do anything with Secret since that is already handled in the previous chapter. What left is the cast to a decimal number and a Yes/No (or boolean).
All we have to do to achieve this is adding two new outputs to our Respond step. One called “EnvVarValueBool” and one called “EnvVarValueNumber”.
The following expression will cast the value to a boolean if the type is yes/no.
if(equals(first(outputs('List_EnvVarDefinition')?['body/value'])['type'],100000002), if(equals(toLower(variables('RespondValue')), 'yes'), true, false), null)
Here is the expression to cast the value to a float if it is of type Decimal number.
if(equals(first(outputs('List_EnvVarDefinition')?['body/value'])['type'],100000001), float(variables('RespondValue')), null)
Problems
There are some problems or at least things to take into consideration when you implement the solution I have described earlier.
- You will get more flow runs impacting both your API limits and license.
- The value from a EnvVar of type Secret isn’t secured when send to the parent flow.
- It is more complicated to get the casted value than using the OOB integration
Conclusion
As you can see there is a solution to the described problem of environment variable caching in Power Automate. It might not be the easiest or pretiest one, but it is working as expected. I hope that Microsoft will change the implementation of the OOB integration to get rid of the caching.
Either you use the OOB functionality and the value is cahced or you accept the mentioned problems and always get the actually value. One has to decide which cons are easier to accept and implement the solution accordingly.
I hope this post helped you. Feel free to contact me with any question or feedback you have.
Attachments
You can also subscribe and get new blog posts emailed to you directly.
Typo in the year here (2nd inset note)? : “This blog post is obsolete. There was a new feature released in July 2023 which pushed changes”