Creating error-proof reusable workflows in UiPath

Target audience: RPA Solution Architects and RPA Developers


Any hardware or software automation needs to consider failures during execution. In Robotic Process Automation (RPA), when automating vital business processes, risk of failure needs to be assessed by personnel involved during the solution design and development stages. Robust workflows can drastically increase robot uptime during production and when the robots fail, it provides sufficient error logs to enable targeted troubleshooting.

During the start of my RPA career, I had the privilege to work with Peter Laken @peter.lacken (MVP - Blue Prism). I would like to thank him for showing me how to handle errors in RPA workflows right from day 1 and for sharing his knowledge of creating robust workflows in Blue Prism.

In this post, I would like to share my learnings from the past two years in RPA and show how you can build an error-proof workflow / automations in UiPath. The same approach can be used in any RPA or software engineering project.

What do I mean by a robust workflow?

  • A workflow, which works as intended
  • A workflow, which fails as intended
  • A workflow, when failed, fails without stopping a process
  • A workflow, when failed lets the developer / maintainer know the source of the failure
  • A workflow, when failed, bubbles up the status to trigger process failure logic
  • A workflow, which is reusable and requires minimal edits when porting from one project to another
  • A workflow, which can either be a part of library or a standalone process

Note that the concept of error handling is the central theme of this approach. Brace yourself for some exceptions handling basics, but I promise you what you will read below may seem simple but a lot of thought has gone into developing this. I have to give a huge shoutout to @otico for the time we spent developing this approach for our RPA CoE.


Edits 23.07.2021 - 16:40
The Use case
In any large RPA project (using REFramework) you will have to create additional workflows within which you design different process logic and later invoke them in the Process.xaml depending on the sequence of your process mentioned in the SDD. Without a way to properly catch and bubble up exceptions in those invoked workflows, the error handling in the REFramework won’t help much. For example, what was the error message from the workflow? where in the Process.xaml did the process fail? By using the proposed workflow along with REFramework, you can build scalable and robust automations.


Walkthrough

There are three main components, which are required to build a robust workflow in UiPath

  1. A try-catch activity to catch exceptions occurring within the workflow
  2. Arguments which communicate failure or success after the execution of the workflow
  3. A unique identifier of the workflow

I will now break our thought process step-by-step.

Step 1 : Try-Catch
In UiPath the try-catch-finally activity allows us to execute business logic in all three sections/blocks, but as developers we need to be aware of their specific functions and limitations. One can also nest a Try-Catch activity in any of the three blocks if needed. Read more about the try-catch activity here : Try Catch (uipath.com)

Step 2 : Create arguments
There are three required arguments which need to be declared in the workflow before proceeding to populate the try sequence

  1. out_ErrorMessage (type String): Allows the entire workflow to send exception messages back to a parent workflow.

  2. out_Success (type Boolean): Allows the parent workflow invoking this workflow to use a flag to determine if the execution within the workflow succeeded or failed.

  3. out_FileName (type String): This retains the name of the workflow where the error occurred.

Note that UiPath does not allow default values on out_arguments. So the next logical step would be to initialize some of these variables.

Step 3 : Initialize workflow
Whenever this workflow is run, we want to set the out_Success flag to False. We do this so that if the logic of the workflow does not work, we do not need to set the value of the out_Success variable.

We also need to specify the name of the workflow being run using out_FileName. This can be done either automatically by using a library from the marketplace called Alphabet.Workflow.Activities . There is thread in the UiPath forum discussing the advantages and disadvantages of using this library .

For this tutorial, I will stick to using a manual assign and update the value of the out_FileName argument.

Step 4 : The logic
After initializing we can start building all kinds of application logic, opening or interacting with UI, performing API calls. In short, anything that can be built in UiPath.

Step 5 : Handling Possible exceptions
We know that this workflow performs a certain function and does not handle any business exceptions. It is always recommended to handle business exceptions in the process level and not in a granular / workflow level. Therefore, we are left with only application exceptions which can occur while performing Step 4.

This gross simplification of possibilities both helps in narrowing down the exception type in the catch activity and ensures that we catch all kinds of system exceptions. Here we choose a generic system exception System.Exception from the dropdown.

When failures do occur, we catch them in the Catch Sequence and assign the exception.Message to the out_ErrorMessage and log that message to the console. The log message ensures persistence of the error message such that if the developer forgets to log the failure message in the workflow invoking this workflow, the error message is still logged at the source workflow.

In the catch block, we do not need to update the out_Success flag as the value is still stored as False from the initialization stage.

Step 6 : Ending logic in the try stage
Since we have handled the exception in the catch stage, what happens when there are no unforeseen errors? The logic written in the workflow should also be capable of handling known / possible failures. For example, if an element is not found after navigating to a page, this will not throw an error (element exists would return a boolean instead), but we as developers know it is not the correct behaviour for this workflow. Such failures have to be handled by the workflow as well.

We can at the end of the workflow use an If condition. This evaluation step has to always be carried out at the end of the workflow.

Note: To demonstrate I use a True flag in the workflow. You will need to assess what the success criteria is after performing your Specific Logic in the workflow.

If : the expected failure was not observed then the workflow function succeeded i.e., assign out_Success as True and log a static information type log message out_FileName+" has successfully finished."

Else : assign out_ErrorMessage: “The given application logic failed.” and log an error type log message : out_FileName+" has failed."

That is all it takes to make an error-proof workflow. The Workflow template in its final form is shown below. Depending on your use case, you can add the required logic to the finally block of the try-catch activity.

Testing the proposed workflow
Case 1 : The happy path, everything works
I use a flag (True) in the If condition in the workflow, you can edit it as per your use case.

Case 2: An expected error occurs
I use a flag (False) in the If condition in the workflow, you can edit it as per your use case.

Case 3: An application error occurs
Here I simulate a failure by reading a text file which does not exist in the logic section of the workflow. Although we know that the robot will fail, our Step 6 will not be triggered. Whenever the robot fails in the logic execution phase, it will automatically move to the catch block.

Invoking the proposed workflow
How to integrate multiple instances of the proposed workflow to a wrapper?

To demonstrate how the integration would look, I created a Main.xaml file where we can invoke the proposed workflow. Remember, we have three out_arguments in our proposed workflow. We can create three variables in the Main.xaml file so that we can store the results from the proposed workflow which is being invoked.

That is not enough, if Main.xaml was our process.xaml file we would want to also confirm that the invoked workflow was successfully executed and if it failed we should have the choice to bubble the exception to the highest level workflow (upstream).

To achieve this, we can use a simple if condition, which uses the Success variable to switch between doing nothing and throwing an application error as shown below.

Case 4 : Invoking workflow which has a happy path
Since we do not have any log messages in the Main.xaml file, the resulting log message is similar to Case 1 when we run the Main.xaml file.

Case 5 : Invoking workflow which has an expected error
An exception is thrown as the Success flag has a value of False. Not to forget, we do have access to the error message obtained from the invoked workflow so if needed we can bubble the exception further. That is what we do with the If condition

Thanks to the error handling, an execution error occurs when we run the Main.xaml file with the details of the error.

Case 6 : Invoking workflow which has an unexpected error
Just like Case 3, here I simulate a failure by reading a text file which does not exist in the logic section of the invoked workflow.

In this case the invoked workflow activates its catch sequence and we get a similar output as Case 5 but with a different error message.

Ending remarks
Nesting the proposed workflow in one another is also possible; this will mean that you need to build logic in the parent workflow / wrapper to handle the bubbled exception from all of the invoked workflows.

This proposed workflow works great with REFramework and it has helped us respond to robot errors swiftly. As you see the proposed workflow satisfies its claims

  • A workflow, which works as intended :white_check_mark:
  • A workflow, which fails as intended :white_check_mark:
  • A workflow, when failed, fails without stopping a process :white_check_mark:
  • A workflow, when failed lets the developer / maintainer know the source of the failure :white_check_mark:
  • A workflow, when failed, bubbles up the status to trigger process failure logic :white_check_mark:
  • A workflow, which is reusable and requires minimal edits when porting from one project to another :white_check_mark:
  • A workflow, which can either be a part of a library or a standalone process :white_check_mark:

We really wish you will try and adopt this approach when developing workflows in UiPath or any other RPA tool. Personally, I can assure you when it comes time to scale your RPA efforts, a standardized error-proof workflow design will be a godsent!


:package:TutorialRobustWorkflow
:nut_and_bolt: Dependencies
:gear: .settings
:gear: .tmh
:scroll:Main.xaml
:spiral_notepad: project.json
:scroll:RobustWorkflowTemplate.xaml

The project files can be found here : TutorialRobustWorkflow.zip (35.9 KB)


We are open to learning from your experience. Do let me / us know if there is something we can improve in this approach.

7 Likes

Great detail here Jeevith that shows a mastery in exception handling - great job and thank you for the accolade :slight_smile:

1 Like

Nice write up but in my opinion you’re missing the most important thing:

Use the Robotic Enterprise Framework !

It has everything you described, is battletested and basically a must use for every serious project. Why reinvent the wheel?

There’s also the ReFramework for Tabular Data if you’re not working with queues but with Excel Files: ReFramework for Tabular Data - RPA Component | UiPath Marketplace

There’s even a framework for document understanding processes: RPA Framework for Document Understanding
Document Understanding Process - New Studio Template

And if you think the ReFramework is lacking something, you could even try to improve it here: GitHub - UiPath-Services/StudioTemplates: UiPath Official Template Repository

2 Likes

Hi @T0Bi,

I think you misunderstood the reason to use the proposed workflow and where to use it. Guess I was not clear about it in the post. My bad.

We are not reinventing the wheel. Far from it!

In any large RPA project (using REFramework) you will have to create additional workflows within which you design different process logic and later invoke them in the Process.xaml depending on the sequence of your process mentioned in the SDD. Without a way to properly catch and bubble up exceptions in those invoked workflows, the error handling in the REFramework won’t help much. For example, what was the error message from the workflow? where in the Process.xaml did the process fail?

I am aware of all the links you shared but my point is that the proposed workflow above can be used in combination with any of the REFramework types. We are staunch believers in the REFramework and have made appropriate edits to it and have our own templates for Dispatcher, Performer and Hybrid REFrameworks. But as the saying goes, the chain is only as strong as the weakest link. We wanted to highlight this and provide inputs to those looking for a solution. Only using REFramework is not a solution.

I will make some edits to the original post to make the use case clear.

2 Likes

Hi @jeevith!

I would like to challenge your statement:

Without a way to properly catch and bubble up exceptions in those invoked workflows, the error handling in the REFramework won’t help much. For example, what was the error message from the workflow? where in the Process.xaml did the process fail?

My recommendation would be to focus more on the process logging and much less on exception bubbling. When done right, there’s rarely a need to bubble exceptions - the combination between the Exception, its stack trace and the logs is enough to pinpoint what went wrong, as well as where, when and why. And REF’s default exception handling is perfectly suited for the job - only detailed logs are needed to paint the full picture.

PS: Retry Scope is also a key item here - you might want to take it into consideration.

1 Like

No, don’t use the REF. It’s bloated, confusing, and overcomplicated for most automations. Poorly designed, IMO. I have my own framework that is much more efficient, easy to use, and easier to maintain.

Hi @Alexandru-Luca,

Let me explain why only using logs is easier said than done in large enterprise projects.

We have used the approach you mentioned a year ago. It is challenging when you have multiple developers working on multiple projects while each of us have the responsibility to maintain the robot developed by the other, typically during personal vacation / leave. Not to forget the dread of looking for a failure in the logs within orchestrator or some dashboard software (needle in a haystack).

If every developer has to decide for themselves where a log message fits best while developing a custom workflow or Process.xaml (REFramework), well then

a) number of logs and their placing can lead to increased development time resulting in the Process.xaml file being too long to review (or wrappers containing number of log messages from multiple invoke workflows)

b) there may be many uncommented or commented log messages from previous developers while the robot needs a hot-fix during production and may lead to incorrect logging during execution.

c) dashboards programs are usually maintained by other teams in the organization and they have their best practices to reduce the logs as they own the databases/index (dashboard product) which can in turn affect performance. In our case, it is Splunk.

d) before or after every invoke workflow in the Process.xaml we will need to decide how to throw an error as well so that the ProcessTransactions state can catch the exception. So there is little merit to limiting the exception handling within an invoked workflow vs. exception from Process.xaml–>ProcessTransactions state. Further this exception from both approaches sets the transaction item status to either a Business / Application failure. So I fail to see how or why you only recommend logging.

On the other hand, if you have a custom standardized workflow which handles all the log messages, success flags and origin / workflow name while also communicating the exception.Message back to Process.xaml, most of the above mentioned challenges will be easy to address (may be point c is still a pain point). REFramework does the rest of the hard work in the ProcessTransactions state.

I would argue that using the expectation.Message along with the Success flag is a safer approach than only relying on log messages set by the developer.

Exception handling is a key area to focus in any RPA project, especially when queues are involved. I am surprised that you are advocating against what is deemed best practice in numerous RPA tools. Exception handling also ensures we can use additional fail-safe logic at any level (either within the Invoked workflow, Process.xaml or at ProcessTransaction state - catch). In short, always assume the robot will not take the happy path.

Only logging will not achieve this, bubbling of some key exceptions is beneficial. For example, the exceptions in Case 5 and Case 6 in my original post can be further handled by the REFramework via Process.xaml—> ProcessTransactions state.


As to the challenge

You are welcome to download the copy of the workflow above and try it on any of the REFrameworks and you will realize why we stand by this approach.


Other remarks

  1. Retry scope is also kind of redundant on wrappers in a REFramework, we already have a number of retries set in the Queue settings. There is no need to have a retry-scope where we invoke workflows. On a more granular level, for example, a click, get text activities are better suited for the retry-scope and should be used whenever possible.

  2. The intention of this post or the original post is not to claim that our approach is the way to go, quite the opposite. This post was my way to document one of the alternatives we found and developed, which could allow bubbling exceptions in REFramework when using custom workflows. If there is a better approach we will learn from it. But show us why the other method is better.

  3. I personally, would still recommend REFframework to UiPath developers as the know-how can be easily used when changing positions. But as @postwick rightly pointed out it does have its limitations, which we must be open to discuss. In the context of this post, we tried to provide an alternative approach to custom workflow integration.

2 Likes

There is a simple solution for this. Need to troubleshoot? Set the Robot to Trace logging.

I personally, would still recommend REFframework to UiPath developers as the know-how can be easily used when changing positions.

I have found that in the real world, the opposite is true. The way REF is designed, with so many XAML files, it’s difficult to find where a step happens in the code. Then once you do, you have to try to decipher the in/out arguments and figure out where a value came from. And then figuring out where the flow goes after an exception is also difficult. Logging doesn’t help unless your developers are excruciatingly detailed about including in the log messages where in the framework the log message was generated.

A simple, single-XAML, top down approach is much easier to hand off to someone else. Within an organization, standards must be set - and followed - for how code is written. That’s how you properly manage hand-off.

Hi @postwick

Thank you for your inputs.
The problem we address is more than the need to just access the log message.

The out_Success flag ensures the invoked workflow did its job, the out_FileName allows us to know where the failure was and out_ErrorMessage captures both expected and unexpected failures in the invoked workflow.

Do try the workflow we posted, may be you will see the benefit of it.

Regarding Trace logs:
The trace based logs will also will not work when invoking custom workflows in REFramework. See below the trace does not mention which workflow the “TestSequence” log message came from. I invoke a workflow and run the Process.xaml file in the REFramework. The log message is within the invoked workflow names TestSequence.xaml

All developers in our organization invested time to learn the REFramework and now we do understand all the workflows and their functions, so it is second nature to us to just continue with it.
Is it bloated? yes. Does it work? yes. Does it scale? yes. As I mentioned before, we have modified it to our use cases.

2 Likes

I have to respectfully disagree. We haven’t had a single new developer who didn’t understand the ReFramework after a simple introduction and building a small process with it.
Most of the ReFrameworks code is completely irrelevant for the developer and he doesn’t have to change it, it simply works.

I’m not sure what kind of processes you’re automating, but the transaction based nature of REF with retries, logging, errorhandling based on transactions is a must have for >95% of our automations.

1 Like

Here’s the solution to your problems:

image

There’s little need to write custom log messages as long as your workflow isn’t a single 2000 activities .xaml.

I can see where @jeevith is coming from and understand his need for this extra level, but I think we never had a scenario where we needed this.

But @postwick just doesn’t understand the REF imo. All of your problems are solved with using the REF. You even have your set standards on how code is written.

When all developers understand the REF, everyone knows exectly what’s going on.

1 Like

I completely understand where you’re coming from, @jeevith!

Indeed, properly handling logs & exception reporting in large enterprise projects is a challenge in itself - just like you mentioned:

We have used the approach you mentioned a year ago. It is challenging when you have multiple developers working on multiple projects while each of us have the responsibility to maintain the robot developed by the other, typically during personal vacation / leave. Not to forget the dread of looking for a failure in the logs within orchestrator or some dashboard software (needle in a haystack).

If every developer has to decide for themselves where a log message fits best while developing a custom workflow or Process.xaml (REFramework)

And they key here is that developers shouldn’t decide individually! A custom protocol and a set of best practices should be decided at organization level and used on top of the REF. My point (which I might not have made 100% clear) is that exception bubbling is a viable option, but it is not the only one. You can still achieve the same level of standardization without it - again, we’re talking about options.

The overall solution is, of course, all developers following the same protocol, as well as having rigorous code-reviews before going into production. Which is exactly as you did - you found a higher-level protocol that you used for standardization. Very nice! :clap:

2 Likes

Hi @T0Bi and @Alexandru-Luca,

Thank you for the reply and open-hearted discussions. We are all passionate about automation and I see that in this thread. Either of the solutions will work and I completely agree that without a standard within a CoE these challenges will only pile up with time. Unfortunately, to REF or not to REF are probably the two schools of thought which will never meet in the middle.

@T0Bi
I am really curious about the Log Entry / Exit properties in your image. I have not see this before and would like to learn more about it. The log message activity only has LogLevel property in my Studio.
image

Can you please guide me as to where or in which activity I can find the Log Entry and Log Exit properties? May be it is a custom log message you built yourself? By the terminology I am assuming Log Entry is when you enter a certain workflow and Log Exit is when you exit that workflow. I am also assuming that these can be optional arguments.

Also what do the values LogEntryType.OnlyInvocation and LogExitType.WithArguments signify? Those namespaces were also not found in the version of Log Message activity I use.

Eagerly waiting for your answer.

1 Like

Maybe I should’ve screenshotted everything instead of assuming you knew of this feature.

image

The invoke workflow file activity has the possibility to log stuff when it’s called/done. You can specify whether or not arguments should be logged and the log level.

I’m not sure in which version this feature was released but it’s definitely in the UiPath.System.Activities 21.4.1

Edit: For clarification, it’s in the InvokeWorkflowFile activity, not the log activity.

4 Likes

Hi @T0Bi,

That is sweet :star_struck:
I can already see some benefits of using your approach.

We can improve our approach by removing the Log message while starting an invoked workflow. We could replace the assign of workflow name and the logging of “ABC workflow has started”. Instead we could use LogEntryType.OnlyInvocation. This will mean that we do not need to change file name we are working on, just rename the entire workflow and we are good to start desinging the required logic within the workflow.

But the exit logs which we use will stay as it provides us with expection.message, known and unknown errors while the LogExitType.OnlySuccessfulReturn does not.

Thanks again for this hidden gem!

2 Likes

Hi @T0Bi,

Just for the sake completeness and before I go to sleep with all these points in my head!

If the workflows are published to a project as a custom UiPath library then those workflows will show up as activities.

So if someone is developing all their application logic in form of a library the approach we suggest above is still suitable. Since in such scenarios, there is no invoke workflow but rather custom activities published via a library.

We use the library approach in one of our projects where we have used the approach mentioned in the post. This way we have traceability of which activity failed in the library, a success flag and the error message from the activity.

But as I said earlier if invoke workflows are used in the REFramework - - - > Process. Xaml, we definitely have to modify/ simplify some of the logging we use and incorporate your suggestions.

Thanks for the idea sparing.

2 Likes

Very well explained but what if I have multiple workflows (more than 100) and as you suggested I have to check the Success flag for each workflow, doesn’t it will impact the performance after using if active for each workflow? Also, is all three variables will be common for all workflows?

Consider the same scenario for library’s and share your thoughts.

Hi @Vinodkumar_Kalkumbe,

You are asking really good questions there. Let me explain.

We have used the above mentioned method in all our workflows both

  1. When workflows are within a UiPath library (which we then consume in the REFramework based dispatcher or performer processes) and
  2. When workflows are within the scope of the REFrameworkf project (dispatcher or performer) itself. i.e., packed within the project.

In both cases the approach we use works great without any noticeable lag or performance penalties in unattended executions. I cannot give you a quantitative answer on this as we have not timed executions to compare the default invoke worklow vs. our approach.

You are right that for example, if you have invoked 100 workflows in Process.xaml file, then there will be 100 checks (if → Success) for the success flag ( one for each invoke ), but the cool thing is that you do not need to save the three variables for each invoke (3 * 300) you need to only declare three variables in the Process.xaml (Success, FailedWorkflowName and ErrorMessage). Each workflow will populate these as they are all going sequential. Note if you are using a for each parallel activity and invoking workflows within them then you probably will need to test this approach works. I doubt it will within a parallel for each.

So back to the example, when the first workflow returns completes successfully, it returns the success flag and null error message and the workflow name. All of these values awill be populated in the corresponding variables.
If after 99 workflows, there is a failure on the 100th invoke, the same Success, ErrorMessage and FailedWorkflowName will be overwritten with new values (False, “Some error message” and “The 100th Workflow”). So the last check (If —> Success=False) will throw an exception as expected.

The maximum number of workflows we have tried in a library is close to 65 and the process has been in production for 7 months without any execution performance issues. The maximum number of workflows packed in a project has been close to 40 and is under testing, with very promising results.

So I can recommend the approach above for Libraries without doubt, but for packed workflows within a project do read the recent posts by @T0Bi in this thread, it has given us some ideas to improve the logging of file names, which we are currently assessing / testing.

2 Likes

a true Robot Master, thank you for sharing.

Hi @jeevith,

Thank you for providing this informative thread to us, I am currently reading the REFramework Documentation and badly needed your opinion. There is a workflow called RunAllTest.xaml file on REFramework wherein it will test all your workflows listed in Tests.xlsx after creating workflows simulating different inputs for success, incorrect data (for business exception), and system exception.

If the ExpectedResult from the Test sheet does not match the result from the Result sheet, the exception will be logged to the comments column and text file.


(image from documentation.)

My TestLog sample

This is all part of REFramework, have you ever tried this?

Thanks,