Skip to content

Commit

Permalink
Use [DebuggerDisableUserUnhandledExceptions]
Browse files Browse the repository at this point in the history
- Add usage of `[DebuggerDisableUserUnhandledExceptions]` in `StrategyHelper` and `RetryEngine` to avoid newer versions of the Visual Studio debugger for breaking for exceptions we are intentionally handling.
- Add copy of `[DebuggerDisableUserUnhandledExceptions]` for use in downlevel versions of .NET that do not contain the attribute.
- Add `net9.0` TFM to potentially include to use the built-in definition of the attribute.
- Add `net8.0` TFM to Polly to resolve dependency resolution issues in the Snippets project.
  • Loading branch information
martincostello committed Oct 16, 2024
1 parent d090973 commit dce141d
Show file tree
Hide file tree
Showing 27 changed files with 79 additions and 26 deletions.
2 changes: 2 additions & 0 deletions src/Polly.Core/Hedging/Controller/TaskExecution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public async ValueTask ResetAsync()
_stopExecutionTimestamp = 0;
}

[DebuggerDisableUserUnhandledExceptions]
private async Task ExecuteSecondaryActionAsync(Func<ValueTask<Outcome<T>>> action)
{
Outcome<T> outcome;
Expand All @@ -218,6 +219,7 @@ private async Task ExecuteSecondaryActionAsync(Func<ValueTask<Outcome<T>>> actio

private async Task ExecuteCreateActionException(Exception e) => await UpdateOutcomeAsync(Polly.Outcome.FromException<T>(e)).ConfigureAwait(Context.ContinueOnCapturedContext);

[DebuggerDisableUserUnhandledExceptions]
private async Task ExecutePrimaryActionAsync<TState>(Func<ResilienceContext, TState, ValueTask<Outcome<T>>> primaryCallback, TState state)
{
Outcome<T> outcome;
Expand Down
1 change: 0 additions & 1 deletion src/Polly.Core/Outcome.TResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,4 @@ internal TResult GetResultOrRethrow()
ExceptionDispatchInfo?.Throw();
return Result!;
}

}
6 changes: 5 additions & 1 deletion src/Polly.Core/Polly.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net6.0;netstandard2.0;net472;net462</TargetFrameworks>
<TargetFrameworks>net9.0;net8.0;net6.0;netstandard2.0;net472;net462</TargetFrameworks>
<AssemblyTitle>Polly.Core</AssemblyTitle>
<RootNamespace>Polly</RootNamespace>
<Nullable>enable</Nullable>
Expand Down Expand Up @@ -36,4 +36,8 @@
<PackageReference Include="System.ComponentModel.Annotations" Condition="!$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'netcoreapp3.1'))" />
</ItemGroup>

<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'net9.0'))">
<Compile Include="$(MSBuildThisFileDirectory)..\Shared\DebuggerDisableUserUnhandledExceptionsAttribute.cs" Link="DebuggerDisableUserUnhandledExceptionsAttribute.cs" />
</ItemGroup>

</Project>
2 changes: 2 additions & 0 deletions src/Polly.Core/ResilienceContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ internal void InitializeFrom(ResilienceContext context, CancellationToken cancel
Properties.AddOrReplaceProperties(context.Properties);
}

#pragma warning disable S3236 // Remove this argument from the method call; it hides the caller information.
[ExcludeFromCodeCoverage]
[Conditional("DEBUG")]
internal void AssertInitialized() => Debug.Assert(IsInitialized, "The resilience context is not initialized.");
#pragma warning restore S3236 // Remove this argument from the method call; it hides the caller information.

internal ResilienceContext Initialize<TResult>(bool isSynchronous)
{
Expand Down
8 changes: 4 additions & 4 deletions src/Polly.Core/ResiliencePipeline.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public async ValueTask ExecuteAsync<TState>(
InitializeAsyncContext(context);

var outcome = await Component.ExecuteCore(
static async (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static async (context, state) =>
{
try
{
Expand Down Expand Up @@ -60,7 +60,7 @@ public async ValueTask ExecuteAsync(
InitializeAsyncContext(context);

var outcome = await Component.ExecuteCore(
static async (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static async (context, state) =>
{
try
{
Expand Down Expand Up @@ -99,7 +99,7 @@ public async ValueTask ExecuteAsync<TState>(
try
{
var outcome = await Component.ExecuteCore(
static async (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static async (context, state) =>
{
try
{
Expand Down Expand Up @@ -140,7 +140,7 @@ public async ValueTask ExecuteAsync(
try
{
var outcome = await Component.ExecuteCore(
static async (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static async (context, state) =>
{
try
{
Expand Down
8 changes: 4 additions & 4 deletions src/Polly.Core/ResiliencePipeline.AsyncT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public async ValueTask<TResult> ExecuteAsync<TResult, TState>(
InitializeAsyncContext<TResult>(context);

var outcome = await Component.ExecuteCore(
static async (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static async (context, state) =>
{
try
{
Expand Down Expand Up @@ -88,7 +88,7 @@ public async ValueTask<TResult> ExecuteAsync<TResult>(
InitializeAsyncContext<TResult>(context);

var outcome = await Component.ExecuteCore(
static async (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static async (context, state) =>
{
try
{
Expand Down Expand Up @@ -127,7 +127,7 @@ public async ValueTask<TResult> ExecuteAsync<TResult, TState>(
try
{
var outcome = await Component.ExecuteCore(
static async (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static async (context, state) =>
{
try
{
Expand Down Expand Up @@ -168,7 +168,7 @@ public async ValueTask<TResult> ExecuteAsync<TResult>(
try
{
var outcome = await Component.ExecuteCore(
static async (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static async (context, state) =>
{
try
{
Expand Down
12 changes: 6 additions & 6 deletions src/Polly.Core/ResiliencePipeline.Sync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public void Execute<TState>(
InitializeSyncContext(context);

Component.ExecuteCoreSync(
static (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static (context, state) =>
{
try
{
Expand Down Expand Up @@ -56,7 +56,7 @@ public void Execute(
InitializeSyncContext(context);

Component.ExecuteCoreSync(
static (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static (context, state) =>
{
try
{
Expand Down Expand Up @@ -92,7 +92,7 @@ public void Execute<TState>(
try
{
Component.ExecuteCoreSync(
static (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static (context, state) =>
{
try
{
Expand Down Expand Up @@ -130,7 +130,7 @@ public void Execute(
try
{
Component.ExecuteCoreSync(
static (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static (context, state) =>
{
try
{
Expand Down Expand Up @@ -169,7 +169,7 @@ public void Execute<TState>(
try
{
Component.ExecuteCoreSync(
static (_, state) =>
[DebuggerDisableUserUnhandledExceptions] static (_, state) =>
{
try
{
Expand Down Expand Up @@ -204,7 +204,7 @@ public void Execute(Action callback)
try
{
Component.ExecuteCoreSync(
static (_, state) =>
[DebuggerDisableUserUnhandledExceptions] static (_, state) =>
{
try
{
Expand Down
12 changes: 6 additions & 6 deletions src/Polly.Core/ResiliencePipeline.SyncT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public TResult Execute<TResult, TState>(
InitializeSyncContext<TResult>(context);

return Component.ExecuteCoreSync(
static (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static (context, state) =>
{
try
{
Expand Down Expand Up @@ -60,7 +60,7 @@ public TResult Execute<TResult>(
InitializeSyncContext<TResult>(context);

return Component.ExecuteCoreSync(
static (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static (context, state) =>
{
try
{
Expand Down Expand Up @@ -95,7 +95,7 @@ public TResult Execute<TResult>(
try
{
return Component.ExecuteCoreSync(
static (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static (context, state) =>
{
try
{
Expand Down Expand Up @@ -131,7 +131,7 @@ public TResult Execute<TResult>(Func<TResult> callback)
try
{
return Component.ExecuteCoreSync(
static (_, state) =>
[DebuggerDisableUserUnhandledExceptions] static (_, state) =>
{
try
{
Expand Down Expand Up @@ -169,7 +169,7 @@ public TResult Execute<TResult, TState>(Func<TState, TResult> callback, TState s
try
{
return Component.ExecuteCoreSync(
static (_, state) =>
[DebuggerDisableUserUnhandledExceptions] static (_, state) =>
{
try
{
Expand Down Expand Up @@ -211,7 +211,7 @@ public TResult Execute<TResult, TState>(
try
{
return Component.ExecuteCoreSync(
static (context, state) =>
[DebuggerDisableUserUnhandledExceptions] static (context, state) =>
{
try
{
Expand Down
2 changes: 2 additions & 0 deletions src/Polly.Core/Retry/RetryHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ private static TimeSpan DecorrelatedJitterBackoffV2(int attempt, TimeSpan baseDe

long ticks = (long)Math.Min(formulaIntrinsicValue * RpScalingFactor * targetTicksFirstDelay, MaxTimeSpanTicks);

#pragma warning disable S3236 // Remove this argument from the method call; it hides the caller information.
Debug.Assert(ticks >= 0, "ticks cannot be negative");
#pragma warning restore S3236 // Remove this argument from the method call; it hides the caller information.

return TimeSpan.FromTicks(ticks);
}
Expand Down
2 changes: 2 additions & 0 deletions src/Polly.Core/Retry/RetryResilienceStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ protected internal override async ValueTask<Outcome<T>> ExecuteCore<TState>(Func
}
}

#pragma warning disable S3236 // Remove this argument from the method call; it hides the caller information.
Debug.Assert(delay >= TimeSpan.Zero, "The delay cannot be negative.");
#pragma warning restore S3236 // Remove this argument from the method call; it hides the caller information.

var onRetryArgs = new OnRetryArguments<T>(context, outcome, attempt, delay, executionTime);
_telemetry.Report<OnRetryArguments<T>, T>(new(ResilienceEventSeverity.Warning, RetryConstants.OnRetryEvent), onRetryArgs);
Expand Down
2 changes: 2 additions & 0 deletions src/Polly.Core/Utils/StrategyHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

internal static class StrategyHelper
{
[DebuggerDisableUserUnhandledExceptions]
public static ValueTask<Outcome<TResult>> ExecuteCallbackSafeAsync<TResult, TState>(
Func<ResilienceContext, TState, ValueTask<Outcome<TResult>>> callback,
ResilienceContext context,
Expand All @@ -29,6 +30,7 @@ public static ValueTask<Outcome<TResult>> ExecuteCallbackSafeAsync<TResult, TSta
return new ValueTask<Outcome<TResult>>(Outcome.FromException<TResult>(e));
}

[DebuggerDisableUserUnhandledExceptions]
static async ValueTask<Outcome<T>> AwaitTask<T>(ValueTask<Outcome<T>> task, bool continueOnCapturedContext)
{
try
Expand Down
1 change: 1 addition & 0 deletions src/Polly.Core/Utils/TaskHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Polly.Utils;

#pragma warning disable S3236 // Remove this argument from the method call; it hides the caller information.
#pragma warning disable S5034 // "ValueTask" should be consumed correctly

internal static class TaskHelper
Expand Down
2 changes: 1 addition & 1 deletion src/Polly.Extensions/Polly.Extensions.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net6.0;netstandard2.0;net472;net462</TargetFrameworks>
<TargetFrameworks>net9.0;net8.0;net6.0;netstandard2.0;net472;net462</TargetFrameworks>
<AssemblyTitle>Polly.Extensions</AssemblyTitle>
<RootNamespace>Polly</RootNamespace>
<Nullable>enable</Nullable>
Expand Down
2 changes: 1 addition & 1 deletion src/Polly.RateLimiting/Polly.RateLimiting.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net6.0;netstandard2.0;net472;net462</TargetFrameworks>
<TargetFrameworks>net9.0;net8.0;net6.0;netstandard2.0;net472;net462</TargetFrameworks>
<AssemblyTitle>Polly.RateLimiting</AssemblyTitle>
<RootNamespace>Polly.RateLimiting</RootNamespace>
<Nullable>enable</Nullable>
Expand Down
2 changes: 1 addition & 1 deletion src/Polly.Testing/Polly.Testing.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net9.0;net8.0;netstandard2.0</TargetFrameworks>
<AssemblyTitle>Polly.Testing</AssemblyTitle>
<RootNamespace>Polly.Testing</RootNamespace>
<Nullable>enable</Nullable>
Expand Down
1 change: 1 addition & 0 deletions src/Polly/Caching/AsyncCacheEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Polly.Caching;

internal static class AsyncCacheEngine
{
[DebuggerDisableUserUnhandledExceptions]
internal static async Task<TResult> ImplementationAsync<TResult>(
IAsyncCacheProvider<TResult> cacheProvider,
ITtlStrategy<TResult> ttlStrategy,
Expand Down
1 change: 1 addition & 0 deletions src/Polly/Caching/CacheEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Polly.Caching;

internal static class CacheEngine
{
[DebuggerDisableUserUnhandledExceptions]
internal static TResult Implementation<TResult>(
ISyncCacheProvider<TResult> cacheProvider,
ITtlStrategy<TResult> ttlStrategy,
Expand Down
1 change: 1 addition & 0 deletions src/Polly/CircuitBreaker/AsyncCircuitBreakerEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

internal static class AsyncCircuitBreakerEngine
{
[DebuggerDisableUserUnhandledExceptions]
internal static async Task<TResult> ImplementationAsync<TResult>(
Func<Context, CancellationToken, Task<TResult>> action,
Context context,
Expand Down
1 change: 1 addition & 0 deletions src/Polly/CircuitBreaker/CircuitBreakerEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Polly.CircuitBreaker;

internal static class CircuitBreakerEngine
{
[DebuggerDisableUserUnhandledExceptions]
internal static TResult Implementation<TResult>(
Func<Context, CancellationToken, TResult> action,
Context context,
Expand Down
1 change: 1 addition & 0 deletions src/Polly/Fallback/AsyncFallbackEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Polly.Fallback;

internal static class AsyncFallbackEngine
{
[DebuggerDisableUserUnhandledExceptions]
internal static async Task<TResult> ImplementationAsync<TResult>(
Func<Context, CancellationToken, Task<TResult>> action,
Context context,
Expand Down
1 change: 1 addition & 0 deletions src/Polly/Fallback/FallbackEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Polly.Fallback;

internal static class FallbackEngine
{
[DebuggerDisableUserUnhandledExceptions]
internal static TResult Implementation<TResult>(
Func<Context, CancellationToken, TResult> action,
Context context,
Expand Down
6 changes: 5 additions & 1 deletion src/Polly/Polly.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;netstandard2.0;net472;net462</TargetFrameworks>
<TargetFrameworks>net8.0;net6.0;netstandard2.0;net472;net462</TargetFrameworks>
<AssemblyTitle>Polly</AssemblyTitle>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProjectType>Library</ProjectType>
Expand All @@ -26,4 +26,8 @@
<ProjectReference Include="..\Polly.Core\Polly.Core.csproj" />
</ItemGroup>

<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'net9.0'))">
<Compile Include="$(MSBuildThisFileDirectory)..\Shared\DebuggerDisableUserUnhandledExceptionsAttribute.cs" Link="DebuggerDisableUserUnhandledExceptionsAttribute.cs" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions src/Polly/Retry/AsyncRetryEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Polly.Retry;

internal static class AsyncRetryEngine
{
[DebuggerDisableUserUnhandledExceptions]
internal static async Task<TResult> ImplementationAsync<TResult>(
Func<Context, CancellationToken, Task<TResult>> action,
Context context,
Expand Down
1 change: 1 addition & 0 deletions src/Polly/Retry/RetryEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace Polly.Retry;

internal static class RetryEngine
{
[DebuggerDisableUserUnhandledExceptions]
internal static TResult Implementation<TResult>(
Func<Context, CancellationToken, TResult> action,
Context context,
Expand Down
Loading

0 comments on commit dce141d

Please sign in to comment.