Power Automate beginners are often tempted to pack a whole process into a single flow. The advantages seem obvious: less clutter, easy to keep an overview over all runs, etc. However, flows quickly become very complicated and fragile.
I'd like to propose an approach that is inspired from asynchronous software design: Chop up a process into stages and handle each stage with an asynchronous child flow.
Each flow, if completed successfully, will then "hand-over" to the next child flow. This approach works very well for automation processes on a Dataverse records (however, the same approach could also be used for SharePoint lists).
Pre-Requesites
- A column carrying a "WorkflowStatus" with a Choice value for each of the stages of the automation process,
examples: "new", "stored", "checked", "confirmed", "rejected", "approved", "completed" - A child flow for each of the stages.
examples: "NewEntry", "StoreEntry", "CheckEntry", "ConfirmationApproval", "RejectEntry", "ApproveEntry", "FinalizeEntry"
Asynchronous Child Flow design (Best Practice)
- Trigger Action = "Manually trigger a flow".
Argument: GUID (of the Dataverse record) - Action "Respond to Power Apps or flow". No return argument.
This will release the calling child flow right away ("Hey, I got it now, you can go have a rest.") - "Get a row by ID (Dataverse)" (using the GUID)
- Assert that the WorkflowStatus is allowed to be processed by the current child flow (=the current stage of the process).
If not, terminate with message to support. - Further assertions on values stored in the record.
Assertions, generally speaking, are expected states, which you don't actually expect to fail. But it's an excellent defensive programming practice to assure that they do meet your expectations. Not only will it make testing easier, assertions will act as built-in sanity checks for future updates to the flow.
If any of these assertions fail, terminate with a message to support. - Only now, set the WorkflowStatus to the name of the current stage. Why so late? Only now, the flow is ready to perform it's core duties - everything before was just prep.
- Perform all operative steps of the current process stage.
In case of errors, terminate with message to support.
Some of the actions may build upon each other. In this case, errors should cause an early termination with message to support. - Launch next child flow in the chain. Even out-of-sequence calls are possible here (#4 would safeguard against illegal out-of-sequence calls).
Robust Error Handling
Create a separate child flow "Support Case".
Trigger Input #2: "pre or post". The calling child flow can specify whether it failed pre- or post-operation. This will define the point of reentry to the process chain (after the support case is resolved).
Advantages of Asynchronous Flow Design
- Flexibility: out-of-sequence calling is possible without becoming a programming nightmare
- Manual reactivation after failture: Should your flow fail and you manage to find the reason for it: Fix the flow (and/or dataverse record), then simply run that flow manually with the GUID that caused the failure. It will then continue its asynchronous journey, as if nothing had happened.
- Efficiency: Each flow only completes a part of the process and then hands-over to the next flow
- Timeout robustness: Remember, each flow can only be running for 30 days, so if you try to chain multiple approvals together, it's very likely, you will sometimes hit this limit. However, if only one approval is allowed per flow, you can very easily extend timeout limits to much much longer process durations. In theory: 30 days x the number of the flows in the process chain.
- Testability: It's very nice to be able to test each stage individually without having to retrigger the whole chain of flows!
No comments:
Post a Comment