#BetaBlogs 18.4 - Global Exception Handler

betafollowup
18_4

#1

We have improved the debugging options in 18.3 but we didn’t stop there. In Studio there were still few options to inspect an exception in a workflow when an error occurs (Try Catch was a life saver so far). So your feedback helped us come up with the Global Exception Handler.

What is it?

Some workflow executions might fail from unforeseen events that can happen at any time, i.e. application pop-ups, automated updates, OS notifications etc.This feature will help you execute a workflow/logic every time an execution error occurs. Let’s call this a Global Handler.

Why do you need this?

The end benefit of defining a Global Exception Handler and attach it to any process execution is that you can design “recovery blocks” where you can try to clean up after the failure and then choose to Ignore the exception, Retry, or Continue the execution. This feature applies to both debug and runtime. During debug you also have an extra option to Break and inspect the issue.

RPA Developers’ job will be easier with this feature since the handler only needs to be defined once and, unlike the Try Catch blocks, does not need to be attached to each activity. It will execute every time an activity fails to execute.

TL;DR: Imagine that you know you have a pesky pop-up that appears once in a while on your desktop which renders the execution to a halt and failure. You can add logic in the handler to remove the pop-up, when that happens, and then continue the execution from the activity which failed by retrying that exact step.

How does it work?

After creating a Process, you can create a Global Exception Handler from the Design tab - New:

The entry point of a Process (usually Main.xaml) cannot be declared as an exception handler. A new sequence template will be created when you add a new global handler, guiding you to best practices to use the Global Exception Handler. This is how it looks like:

The handler will execute every time an exception occurs both during debug and during runtime. During debug, Studio will ask to choose from one of the Break/Continue/Ignore/Retry options. During runtime, this option can be set inside the handler via “ErrorAction” (see snapshot above). Studio Debug options are:

  • Break: suspends the current execution so that you can inspect what happened
  • Ignore: continues execution from the next activity
  • Retry: will retry executing the current activity
  • Continue: will execute the global handler (which will be executed during runtime as well, when set)

There are a few other behaviors in place which you need to know. As said above, this only applies to Processes, not Libraries. In this case, if an exception occurs in an activity:

  • If it’s surrounded by a Try Catch block, execution continues inside the Catch block as before.
  • If Global Exception Handler is NOT defined for your Process, execution suspends right where the activity threw the exception and you can choose to Retry, Ignore, Continue or Break the execution.
  • Any xaml (that is NOT the entry workflow) can be Set as Exception Handler from the contextual menu in Project panel.
  • There can be only one handler per process.

2018.4 Community Beta Release
2018.4 Community Beta Release
How to handle random popup
Tackling with unexpected pop-ups in the automation process
2018.4 Community Beta Release
#4

Neat that everyone seems to prefer the dark theme (I’ll never understand why :-), but for official threads & documentation, can you please use the light theme? Dark screenshots like that are much harder to read, and I pity the printer of anyone who wants to print a UiPath thread or doc page…


#5

You’re not cool unless you use Dark themes. :laughing:


#6

Agreed. Though I do appreciate the UiPath team for considering and delivering a darker theme, I personally still prefer the lighter one, and I’m one of those people who really wanted to like it, but that just didn’t happen (so far at least.) I guess that’s probably because once you use the tool with a specific theme for some time, it kind of grows on you.


#7

Team any suggestion on pause and resume feature. cant find this functionality.


#8

Hi,

It looks like that when you remove the exception handler from the project, the studio will break (debug or not) on every exception, even the ones handled by a Try catch.

Is there something planned to safely remove one handler from project?

Edit : This is actually already implemented and issue do not occur if you use “Remove handler” feature.

image
What I described is happening only if you remove file from Windows explorer.

Cheers


#9

Agreed. @ovi FYI. Going forward we’ll use Classic Theme for posts. Note that the Dark Theme will be an experimental feature in 18.4.


#10

@Florent_Salendres thanks for the feedback, i’ll get back to you on this.


#11

Pleasure is mine.
Note that all worked out again when removing the Global handler reference inside the project.json (under runtile settings) file

Cheers


#12

I do not agree. I agree for the official documentation. The forum is not meant to be printed and I would not expect the guys posting to switch their theme every time they are posting something. I would make it free for all.


#13

At last waiting was Done :star_struck: … moving to Dark Theme :bat:


#14

This can be found by right-clicking the .xaml file in the project tree. This was not clear from the original post.


#15

I guess I must be obtuse, but at first glance, this feature doesn’t feel intuitive to me. Surely I’m misunderstanding how to use it.

  1. I created a blank project and added this global handler

  2. I added a throw into the Main.xaml, and then a log message after that to see whether the entire process would complete after the exception was handled (presumably by global handler). I also modified the global handler’s log message activity with a prefix of “Inside handler”, so I could follow the execution path in the output log.

  3. Running in debug mode presented a dialog, as described above, which allowed me to manually decide whether to break, ignore, retry, or continue. I see where this might be helpful, because I can control what happens, and most importantly, drop into the code to inspect what happened, like a dynamically created breakpoint.

  4. However, when I ran in normal mode, this dialog never pops up to allow the user to choose. If I leave the “Choose next behavior” programmatic assignment as ErrorAction.Continue, the exception was rethrown, the global handler was subsequently invoked twice, and then the process ended, skipping over my final log message.

  5. When I instead changed the handler’s choice to ErrorAction.Retry, my process went into an infinite loop because the error kept getting re-thrown, handled, re-thrown, etc.

So given that this global handler could get triggered by ANY kind of unexpected exception, some of which should not be retried per the example above, are we supposed to load up this “global handler” with dozens of conditional tests to automatically determine the appropriate choice to handle any number of possible unexpected exceptions?

The documentation didn’t make the usage any more clear to me.


#16

Hi
Please kindly explain the Global Exception Handler with an example(.xaml file)

Thanks & Regards
Srihari


#17

Hi @octechnologist, Thanks for the feedback. Indeed, we need more info around this inside the documentation and could possibly improve a few things in the product in a future version.

Let me try to confirm a few things before diving into an example based explanation.

Regarding point #3

Indeed, the reason for this pop-up is to try to reproduce during debugging the exact behavior which would happen at runtime. During runtime, if an exception occurs and a handler is defined, the handler would automatically execute and at the end of the handler it will “Continue”, “Ignore” or “Retry” depending on what the handler says/decides/defines. The steps would hence be:

  • activity throws exception
  • handler kicks in
  • execution continues based on what the handler decides

Regarding point #4

Indeed, during runtime, the debugging dialog never appears. The debugging dialog is for debuggins purposes solely. In your case, if the handler decided to continue, when the exception occured, this is an expected behavior. The fact that the handler was executed twice is also expected in a Continue scenario. In fact it will execute at each level in the stack tree. I.e. if your activity had a sequence parent and that parent had a sequence parent and so on, the exception will bubble up in the tree and be thrown at each level. This actually allows you as a developer to control what to do in the handler at each level.

In order to identify which activity threw the error, you can inspect the errorInfo input argument of the handler. This argument contains some viable information that allows you to control what the handler does depending on your situation:

  • errorInfo.ActivityInfo is the name of the activity which failed right now
  • errorInfo.RetryCount is the number of times this activity was retried already

Now, your final log message was skipped because when Continue is used, the exception is thrown to the parent (as explained).

Regarding point #5

This is again tricky. The default GlobalHandler template inside Studio does not treat this scenario and maybe there’s room for improvement. In your example it is expected to go into an infinite loop because the default handler does not say when it should Stop retrying”. Ideally you should use the errorInfo.RetryCount information to control that.

Here’s an example

I have a project where i click on a Notepad window. The notepad window is now closed so if executed it will obviously fail.

image

When i debug this, it will fail and the debugging dialog will appear.

image

I will click Retry here twice which means the click activity will be retried twice. Afterwards i will click Continue.
When i click Continue, it will enter the handler. Remember, this is how we defined the behavior for these buttons so that we can simulate what happens during runtime and debug properly.

I modified my handler to take into account the RetryCount and the name of the activity (ActivityInfo).

When the handler is entered you can inspect the errorInfo object.

image

As you can see, my handler looks at how many times this particular activity which failed was retried, after the handler was executed. If it was retried X times, then i tell the handler to throw the exception and stop retrying.

Now, this is a simple example but we can expand on this if needed. Please let me know what you think now.

Finally to answer your last question

The idea of this handler was that you can control what to do in case of a failure. Imagine an example where your UI automation might fail because of an update pop-up from a certain application on your machine (like Adobe, Windows, etc.). If you define a handler that simply closes that pop-up and retries the execution (in my example retries clicking inside Notepad), then you can simply continue the execution without having to re-execute the job and complete successfully. This has many applications in real life. Assuming that now it’s a bit more clear - Can you think of one that helps you?

Cheers,


#19

Hello all,

I’ve taken the feedback from all of you into consideration and included more explanations in the Global Exception Handler page, part of the Studio guide.

Based on the above explanations from @MirceaGrigore, I added an example in the documentation, provided steps for creating and editing a Global Handler in a workflow, adding a RetryCount method to count the number of times it retries the activity which faulted and an If activity to condition the Global Handler to stop when a certain number of retries is reached.

There are images too and the example is downloadable. Check it out and let us know what you think.

Thank you all for your feedback, it helps us continuously improve and up our game.


#20

Really cool feature. Any thoughts on how this will be used in REFramework or change best practice for Exceptions?
I guess TryCatch will only be used for special occasions and not needed as an umbrella anymore.


#21

This improvement is very useful.
Is it possible to real time change Exception Handler Workflow by modifying project.json?
Or is there any other way to do that.


#22

Hi, I haven’t seen this mentioned so I thought i would.

In packages, the dependencies versions are missing a closing square bracket, as show in the picture below.
image

Hope this helped


#23

I also really don’t know how are we supposed to use this in a non-toy context.

I downloaded the example and altered a little bit:
Main invokes Child
Child has Sequence { Sequence { Sequence { TypeInto (that fails, 1000ms timeout) [rest is irrelevant]
Retry count left as is, on out of retries used .Continue.
I stopped it manually after 7 minutes (!) since it was getting boring. It seemed to alternate between retrying the TypeInto and the containing Sequence, although I might be mistaken and it would eventually finish.

Next try:
As above, but after retrying used .Ignore
As expected it continued as if everything was all right. Which I fail to see the point of (ContinueOnError on RetryScope does the same)

.Abort just stops execution outright, so that doesn’t need testing, but I don’t know when you would want that in a real scenario.

Does it really mean that the global handler needs to be configured to only handle very specific activities which needs to be identified only by:

  • Exception info
  • Activity info

Available Exception info seems to be exactly the same as with normal Catch.
Activity info seems to have:

  • Id (which will change pretty much every time you change the workflow in question and also is not-unique on project level)
  • InstanceId (which is execution order dependant and if you retry anything will be off)
  • Name (or to be precise - DisplayName of the activity)
  • Type (class name of the activity in question)

There is also access to:

  • Variables (but only direct scope variables, so only for things that have their own variable scope? It’s confusing)
  • Arguments (which seem to get activity Arguments [it was a surprise - shouldn’t it be under ActivityInfo?], so to use them properly you first need to know the type)

So there is no context. I guess we could try to identify activities by a combination of Type + Arguments + DisplayName (flimsy and still not guaranteed to be unique), but still we’d have no access to the context. At this point I question the usability of it outside logging, because at that point we’re writing handling for a specific activity throwing an exception, but in a completely different place that someone inevitably will forget to update or even if not, you can’t reason about the execution flow of any workflow anymore without double checking the global handler.

Even for logging (with no retries and .Continue action), it fires on each stack level, so there’s a ton of spam there.

It also has a very weird interaction with TryCatch - since the handler doesn’t know the context, you can very easily mess up the logic. From short testing it even came to mind that the moment you add a global handler, you can’t even trust the code to get to the catch part at all, since something else can “handle” (or straight up ignore if it’s misconfigured) the exception.

Execution times in general seem to increase by 1-2 orders of magnitude, unless .Retry is called just for very specific activities, at which point - why run the risk?

For debugging - this is a great addition (especially the Break option).
For production runs - I see more risks than gains.

@MirceaGrigore, @alexandra.vaidos - could you give a non-trivial example of how is this supposed to be configured? Right now I can only think of projects so simple that a global handler is not needed or so complex that I’d not dare to introduce it. Or in essence - what problem is this trying to solve?
(also I’m yet to see those truly “random” popups that keep being mentioned - all I saw so far had actually predictable reasons, but I’m open to be proven wrong).

Edit:
Found one - on unstable network environments it could be used to retry orchestrator calls (didn’t test if it would perform correctly, but theoretically it should). Still would like to see how the authors would configure this for a non-trivial project.