Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use [DebuggerDisableUserUnhandledExceptions] #2254

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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!;
}

}
4 changes: 4 additions & 0 deletions src/Polly.Core/Polly.Core.csproj
Original file line number Diff line number Diff line change
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
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]
martincostello marked this conversation as resolved.
Show resolved Hide resolved
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
4 changes: 4 additions & 0 deletions src/Polly/Polly.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 5 additions & 0 deletions src/Polly/Timeout/AsyncTimeoutEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

internal static class AsyncTimeoutEngine
{
[DebuggerDisableUserUnhandledExceptions]
internal static async Task<TResult> ImplementationAsync<TResult>(
Func<Context, CancellationToken, Task<TResult>> action,
Context context,
Expand Down Expand Up @@ -57,7 +58,11 @@ internal static async Task<TResult> ImplementationAsync<TResult>(
// See https://github.com/App-vNext/Polly/issues/722.
if (!combinedTokenSource.IsCancellationRequested && timeoutCancellationTokenSource.IsCancellationRequested)
{
#if NET8_0_OR_GREATER
await combinedTokenSource.CancelAsync().ConfigureAwait(false);
#else
combinedTokenSource.Cancel();
#endif
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/Polly/Timeout/TimeoutEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Polly.Timeout;

internal static class TimeoutEngine
{
[DebuggerDisableUserUnhandledExceptions]
internal static TResult Implementation<TResult>(
Func<Context, CancellationToken, TResult> action,
Context context,
Expand Down
21 changes: 21 additions & 0 deletions src/Shared/DebuggerDisableUserUnhandledExceptionsAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma warning disable
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// Adapted from https://github.com/dotnet/runtime/blob/bffe34e0c7ff8a05e79d884ed8447426aae17bfb/src/libraries/System.Private.CoreLib/src/System/Diagnostics/DebuggerDisableUserUnhandledExceptionsAttribute.cs
// See the following links for more information and context:
// https://github.com/dotnet/runtime/issues/103105,
// https://github.com/dotnet/runtime/pull/104813
// https://github.com/dotnet/aspnetcore/issues/57085

namespace System.Diagnostics;

/// <summary>
/// If a .NET Debugger is attached which supports the Debugger.BreakForUserUnhandledException(Exception) API,
/// this attribute will prevent the debugger from breaking on user-unhandled exceptions when the
/// exception is caught by a method with this attribute, unless BreakForUserUnhandledException is called.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
internal sealed class DebuggerDisableUserUnhandledExceptionsAttribute : Attribute
{
}