-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Debugging with Polly in Visual Studio
ℹ️ This documentation describes the previous Polly v7 API. If you are using the new v8 API, please refer to pollydocs.org.
When you define a Polly exception-handling policy, the policy will internally catch matched exceptions and handle them as the policy defines: orchestrate a retry; update circuit-breaker statistics; or channel execution to a fallback.
Debugging such executions can however be noisy in Visual Studio: commonly-used settings cause Visual Studio to break on each exception the policy handles.
A better experience debugging with Polly in the mix can be achieved by configuring Visual Studio debugger settings to break on Just My Code, to continue on so-called user-unhandled exceptions, and by specifying whether to break depending on which module throws the exception.
First, you likely want to set the debug setting 'Just My Code'.
(image via https://docs.microsoft.com/visualstudio/debugger/just-my-code)
This tells the VS debugger that you don't want to step through the code of the .NET implementation, nor of third party libraries you may be using - this includes Polly and third-party libraries you might be calling through Polly.
Next, we need to unpack what Visual Studio means by a User-unhandled exception. The Visual Studio Debugger may break for an exception, saying it is user-unhandled:
(image via https://docs.microsoft.com/visualstudio/debugger/managing-exceptions-with-the-debugger)
Many have commented that Visual Studio's terminology user-unhandled is confusing.
- It does not mean the exception is unhandled.
- It also does not mean your user code won't handle the exception eventually (once code flow has been allowed to continue, via the debugger controls).
Rather, the debugger may break saying an exception is user-unhandled if the exception is first handled by non-user code. Reference: https://blogs.msdn.microsoft.com/visualstudioalm/2015/01/07/understanding-exceptions-while-debugging-with-visual-studio/.
By "user-unhandled", the error message is meaning that user-code didn't handle the exception before it propagated out of user-code into non-user-code.
If an exception is going to be handled by non-user code (for example a Polly policy), why then does the debugger (by default) break for it?
It does this (per MSDN) so that you still have a chance to see the exception at source where it occurred - it is an exception, after all.
However, this behaviour is what can make step-debugging with Polly noisy. For instance, if you have five retries configured and all fail, step-debugging this will break all six times (first try and five retries) the exception is thrown.
You have two options to deal with this:
- Change the Visual Studio debugger settings to not break on user-unhandled exceptions (see section immediately below)
- If you control the code where the exception is first thrown, use attributes to tell the debugger not to step through that code (skip down to the section on attributes)
To reduce the noise when step-debugging exceptions handled by a Polly policy, in Visual Studio 2015 onwards, you can adjust debugging settings to specify that you do not want to break when a given exception type is 'user-unhandled'.
Follow the instructions here to not break when a specific exception is user-unhandled (ie handled by Polly) in Visual Studio 2015, section Using the Context Menu
Follow the instructions here to not break when a specific exception is user-unhandled (ie handled by Polly) in Visual Studio 2017, section Tell the debugger to continue on user-unhandled exceptions
For example, when using a Polly policy to handle System.Io.IoException
, you might specify not to break when this is 'user-unhandled' (as we learnt above, this includes 'handled by Polly').
This approach can have limitations, in that you might want the debugger not to break on IoException
s on that particular code path; but you might still want it to break if those exceptions are thrown elsewhere. Visual Studio 2015 does not give you that level of control, but Visual Studio 2017 comes closer to doing so. With Visual Studio 2017, you can specify to break or not break according to conditions: for example according to which module is throwing.
Image via https://docs.microsoft.com/visualstudio/debugger/managing-exceptions-with-the-debugger: Follow the instructions under Add conditions to an exception
If for example you are using Polly to handle exceptions thrown by a third-party library or particular System.*.dll
, you could use Visual Studio's fine control to specify that the debugger should not break when the exception is thrown by that library. However, if the exception was unexpectedly thrown elsewhere in your code, the debugger would continue to break.
If you control the code where the exception is being thrown, another way to smooth the debugging experience is to add the [DebuggerStepThrough]
or [DebuggerNonUserCode]
attribute to methods where the exception is thrown - this is an alternative to configuring the debugger to continue on so-called user-unhandled exceptions.
Note that way back in Visual Studio 2015, this behaviour got broken, as this issue explored. It is confirmed working again in Visual Studio 2019.
Breaking on a 'first-chance' (or user-unhandled first-chance) exception means that the debugger breaks at the first chance after the exception is thrown (if configured to do so), even if you do have a try/catch
that will handle that exception later.
For completeness, an exception not handled by a try/catch
is known as a 'second-chance' or 'last-chance' exception. If there is no code handling for 'second-chance' or 'last-chance' exceptions, the debugger will always break on them.
From v7.10, Polly supports Source Link. This means that you can step into Polly code (if useful) as you debug. To enable this, in Visual Studio, in Tools -> Options -> Debugging
:
- uncheck
Enable Just my code
- check
Enable Source Link support
.
- Home
- Polly RoadMap
- Contributing
- Transient fault handling and proactive resilience engineering
- Supported targets
- Retry
- Circuit Breaker
- Advanced Circuit Breaker
- Timeout
- Bulkhead
- Cache
- Rate-Limit
- Fallback
- PolicyWrap
- NoOp
- PolicyRegistry
- Polly and HttpClientFactory
- Asynchronous action execution
- Handling InnerExceptions and AggregateExceptions
- Statefulness of policies
- Keys and Context Data
- Non generic and generic policies
- Polly and interfaces
- Some policy patterns
- Debugging with Polly in Visual Studio
- Unit-testing with Polly
- Polly concept and architecture
- Polly v6 breaking changes
- Polly v7 breaking changes
- DISCUSSION PROPOSAL- Polly eventing and metrics architecture