fix(common): classify request cancellation in profiler
Preserve legacy profiler contracts and record expected cancellation below error level.
This commit is contained in:
@@ -6,12 +6,26 @@ using Serilog;
|
||||
public interface IProfiler
|
||||
{
|
||||
Task<T> MeasureExecutionAsync<T>(Func<Task<T>> function, string blockName = "");
|
||||
Task<T> MeasureExecutionAsync<T>(Func<Task<T>> function, string blockName, CancellationToken cancellationToken)
|
||||
{
|
||||
return MeasureExecutionAsync(function, blockName);
|
||||
}
|
||||
|
||||
Task MeasureExecutionAsync(Func<Task> action, string blockName = "");
|
||||
Task MeasureExecutionAsync(Func<Task> action, string blockName, CancellationToken cancellationToken)
|
||||
{
|
||||
return MeasureExecutionAsync(action, blockName);
|
||||
}
|
||||
}
|
||||
|
||||
public class Profiler(ILogger logger) : IProfiler
|
||||
{
|
||||
public async Task<T> MeasureExecutionAsync<T>(Func<Task<T>> function, string blockName = "")
|
||||
public Task<T> MeasureExecutionAsync<T>(Func<Task<T>> function, string blockName = "")
|
||||
{
|
||||
return MeasureExecutionAsync(function, blockName, CancellationToken.None);
|
||||
}
|
||||
|
||||
public async Task<T> MeasureExecutionAsync<T>(Func<Task<T>> function, string blockName, CancellationToken cancellationToken)
|
||||
{
|
||||
logger.ForContext("PerformanceLog", true).Information("{BlockName} - Start", blockName);
|
||||
|
||||
@@ -42,6 +56,13 @@ public class Profiler(ILogger logger) : IProfiler
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
logger
|
||||
.ForContext("PerformanceLog", true)
|
||||
.Debug("{BlockName} - Canceled", blockName);
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex) // NOSONAR
|
||||
{
|
||||
logger
|
||||
@@ -51,12 +72,17 @@ public class Profiler(ILogger logger) : IProfiler
|
||||
}
|
||||
}
|
||||
|
||||
public async Task MeasureExecutionAsync(Func<Task> action, string blockName = "")
|
||||
public Task MeasureExecutionAsync(Func<Task> action, string blockName = "")
|
||||
{
|
||||
return MeasureExecutionAsync(action, blockName, CancellationToken.None);
|
||||
}
|
||||
|
||||
public async Task MeasureExecutionAsync(Func<Task> action, string blockName, CancellationToken cancellationToken)
|
||||
{
|
||||
await MeasureExecutionAsync<object?>(async () =>
|
||||
{
|
||||
await action();
|
||||
return null;
|
||||
}, blockName);
|
||||
}, blockName, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,20 @@ Shared common utilities for HrynCo applications.
|
||||
- Tree traversal helpers
|
||||
- Time and profiling helpers
|
||||
|
||||
## Profiling and cancellation
|
||||
|
||||
`IProfiler.MeasureExecutionAsync` supports both result-returning and action delegates. Existing overloads keep their original behavior. Pass a cancellation token as the third argument when profiling work associated with a request:
|
||||
|
||||
```csharp
|
||||
await profiler.MeasureExecutionAsync(() => LoadItemsAsync(cancellationToken), "LoadItems", cancellationToken);
|
||||
```
|
||||
|
||||
If the delegate throws `OperationCanceledException` (including `TaskCanceledException`) and the supplied token is canceled, the profiler writes a Debug cancellation event with `PerformanceLog = true` and no attached exception, then rethrows the original exception. An `OperationCanceledException` with an uncanceled or absent token, and any other exception even with a canceled token, remain Error events with the exception attached. Failed or canceled operations do not write a successful End measurement.
|
||||
|
||||
The supplied token controls log classification; the caller must pass it to the operation itself. The profiler does not cancel the delegate or reject successful work when the token is canceled.
|
||||
|
||||
Custom implementations of `IProfiler` that implement only the original overloads remain compatible. The new interface overloads default to the original methods; custom implementations must override them to add token-aware log classification.
|
||||
|
||||
## Packaging
|
||||
|
||||
This package is intended for reuse through NuGet. The test project is excluded from packing.
|
||||
|
||||
Reference in New Issue
Block a user