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

Add support for .NET 8 #1144

Merged
merged 12 commits into from
Nov 14, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with:
name: packages-${{ matrix.os_name }}
path: ./artifacts/nuget-packages
path: ./artifacts/package/release
if-no-files-found: error

- name: Upload signing file list
Expand Down
5 changes: 5 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>
<PropertyGroup>
<UseArtifactsOutput>true</UseArtifactsOutput>
</PropertyGroup>
</Project>
12 changes: 3 additions & 9 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<MicrosoftExtensionsVersion>7.0.0</MicrosoftExtensionsVersion>
<MicrosoftExtensionsVersion>8.0.0</MicrosoftExtensionsVersion>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<PollyVersion>8.1.0</PollyVersion>
</PropertyGroup>
Expand All @@ -10,6 +10,7 @@
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
<PackageVersion Include="GitHubActionsTestLogger" Version="2.3.3" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" />
<PackageVersion Include="Microsoft.Bcl.TimeProvider" Version="$(MicrosoftExtensionsVersion)" />
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsVersion)" />
Expand All @@ -20,6 +21,7 @@
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsVersion)" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="$(MicrosoftExtensionsVersion)" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="$(MicrosoftExtensionsVersion)" />
<PackageVersion Include="Microsoft.Extensions.TimeProvider.Testing" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
<PackageVersion Include="MinVer" Version="4.3.0" />
Expand All @@ -41,12 +43,4 @@
<PackageVersion Include="xunit" Version="2.6.1" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.3" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework) == 'net6.0'">
<PackageVersion Update="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageVersion Update="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
</ItemGroup>
<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'netcoreapp3.1'))">
<PackageVersion Update="Microsoft.Extensions.Options" Version="2.2.0" />
<PackageVersion Update="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion bench/Polly.Benchmarks/Polly.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<IsPackable>false</IsPackable>
<OutputType>Exe</OutputType>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ProjectType>Benchmark</ProjectType>
<NoWarn>$(NoWarn);CA1822;SA1414;IDE0060</NoWarn>
Expand Down
2 changes: 1 addition & 1 deletion bench/Polly.Core.Benchmarks/Polly.Core.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net7.0</TargetFrameworks>
<TargetFrameworks>net8.0;net7.0</TargetFrameworks>
<RootNamespace>Polly</RootNamespace>
<ImplicitUsings>true</ImplicitUsings>
<ProjectType>Benchmark</ProjectType>
Expand Down
10 changes: 3 additions & 7 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var artifactsDir = Directory("./artifacts");
var testResultsDir = System.IO.Path.Combine(artifactsDir, Directory("test-results"));

// NuGet
var nupkgDestDir = System.IO.Path.Combine(artifactsDir, Directory("nuget-packages"));
var nupkgDestDir = System.IO.Path.Combine(artifactsDir, Directory("package"), Directory("release"));

// Stryker / Mutation Testing
var strykerConfig = MakeAbsolute(File("./eng/stryker-config.json"));
Expand Down Expand Up @@ -65,17 +65,13 @@ Teardown(_ =>
Task("__Clean")
.Does(() =>
{
DirectoryPath[] cleanDirectories = new DirectoryPath[]
CleanDirectories(new[]
{
testResultsDir,
nupkgDestDir,
artifactsDir,
strykerOutput
};

CleanDirectories(cleanDirectories);

foreach (var path in cleanDirectories) { EnsureDirectoryExists(path); }
});

foreach (var path in solutionPaths)
{
Expand Down
1 change: 1 addition & 0 deletions eng/Library.targets
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

<PropertyGroup Label="NuGet package validation">
<EnablePackageValidation Condition="'$(EnablePackageValidation)' == ''">true</EnablePackageValidation>
<!-- TODO Bump to 8.2.0 once published to NuGet.org -->
<PackageValidationBaselineVersion Condition="'$(PackageValidationBaselineVersion)' == ''">8.1.0</PackageValidationBaselineVersion>
</PropertyGroup>

Expand Down
3 changes: 2 additions & 1 deletion eng/stryker-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"block",
"statement"
],
"target-framework": "net7.0",
"language-version": "Preview",
"target-framework": "net8.0",
"thresholds": {
"high": 100,
"low": 100
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "7.0.403",
"version": "8.0.100",
"allowPrerelease": false,
"rollForward": "latestMajor"
}
Expand Down
4 changes: 2 additions & 2 deletions src/Polly.Core/CircuitBreaker/CircuitBreakerManualControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ namespace Polly.CircuitBreaker;
public sealed class CircuitBreakerManualControl
{
private readonly object _lock = new();
private readonly HashSet<Func<ResilienceContext, Task>> _onIsolate = new();
private readonly HashSet<Func<ResilienceContext, Task>> _onReset = new();
private readonly HashSet<Func<ResilienceContext, Task>> _onIsolate = [];
private readonly HashSet<Func<ResilienceContext, Task>> _onReset = [];
private bool _isolated;

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,14 @@ private static bool IsDateTimeOverflow(DateTimeOffset utcNow, TimeSpan breakDura

private void EnsureNotDisposed()
{
#if NET8_0_OR_GREATER
ObjectDisposedException.ThrowIf(_disposed, this);
#else
if (_disposed)
{
throw new ObjectDisposedException(nameof(CircuitStateController<T>));
}
#endif
}

private void CloseCircuit_NeedsLock(Outcome<T> outcome, bool manual, ResilienceContext context, out Task? scheduledTask)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ internal sealed class ScheduledTaskExecutor : IDisposable

public void ScheduleTask(Func<Task> taskFactory, ResilienceContext context, out Task task)
{
#if NET8_0_OR_GREATER
ObjectDisposedException.ThrowIf(_disposed, this);
#else
if (_disposed)
{
throw new ObjectDisposedException(nameof(ScheduledTaskExecutor));
}
#endif

var source = new TaskCompletionSource<object>();
task = source.Task;
Expand Down
12 changes: 0 additions & 12 deletions src/Polly.Core/CompatibilitySuppressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@
<Left>lib/netstandard2.0/Polly.Core.dll</Left>
<Right>lib/net6.0/Polly.Core.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Polly.CircuitBreaker.BrokenCircuitException`1.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)</Target>
<Left>lib/netstandard2.0/Polly.Core.dll</Left>
<Right>lib/net6.0/Polly.Core.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Polly.CircuitBreaker.IsolatedCircuitException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)</Target>
Expand All @@ -25,10 +19,4 @@
<Left>lib/netstandard2.0/Polly.Core.dll</Left>
<Right>lib/net6.0/Polly.Core.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Polly.Timeout.TimeoutRejectedException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)</Target>
<Left>lib/netstandard2.0/Polly.Core.dll</Left>
<Right>lib/net6.0/Polly.Core.dll</Right>
</Suppression>
</Suppressions>
12 changes: 10 additions & 2 deletions src/Polly.Core/Hedging/Controller/HedgingExecutionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ internal sealed class HedgingExecutionContext<T> : IAsyncDisposable
{
public readonly record struct ExecutionInfo<TResult>(TaskExecution<T>? Execution, bool Loaded, Outcome<TResult>? Outcome);

private readonly List<TaskExecution<T>> _tasks = new();
private readonly List<TaskExecution<T>> _executingTasks = new();
private readonly List<TaskExecution<T>> _tasks = [];
private readonly List<TaskExecution<T>> _executingTasks = [];
private readonly ObjectPool<TaskExecution<T>> _executionPool;
private readonly TimeProvider _timeProvider;
private readonly int _maxAttempts;
Expand Down Expand Up @@ -122,7 +122,11 @@ public async ValueTask DisposeAsync()

using var delayTaskCancellation = CancellationTokenSource.CreateLinkedTokenSource(PrimaryContext!.CancellationToken);

#if NET8_0_OR_GREATER
var delayTask = Task.Delay(hedgingDelay, _timeProvider, delayTaskCancellation.Token);
#else
var delayTask = _timeProvider.Delay(hedgingDelay, delayTaskCancellation.Token);
#endif
Task<Task> whenAnyHedgedTask = WaitForTaskCompetitionAsync();
var completedTask = await Task.WhenAny(whenAnyHedgedTask, delayTask).ConfigureAwait(ContinueOnCapturedContext);

Expand All @@ -133,7 +137,11 @@ public async ValueTask DisposeAsync()

// cancel the ongoing delay task
// Stryker disable once boolean : no means to test this
#if NET8_0_OR_GREATER
await delayTaskCancellation.CancelAsync().ConfigureAwait(ContinueOnCapturedContext);
#else
delayTaskCancellation.Cancel(throwOnFirstException: false);
#endif

await whenAnyHedgedTask.ConfigureAwait(ContinueOnCapturedContext);

Expand Down
3 changes: 2 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>net6.0;netstandard2.0;net472;net462</TargetFrameworks>
<TargetFrameworks>net8.0;net6.0;netstandard2.0;net472;net462</TargetFrameworks>
<AssemblyTitle>Polly.Core</AssemblyTitle>
<RootNamespace>Polly</RootNamespace>
<Nullable>enable</Nullable>
Expand Down Expand Up @@ -29,6 +29,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Condition="!$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'netcoreapp3.1'))" />
<PackageReference Include="Microsoft.Bcl.TimeProvider" Condition="!$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'net8.0'))" />
<PackageReference Include="System.Threading.Tasks.Extensions" Condition="!$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'netcoreapp3.1'))" />
<PackageReference Include="System.ValueTuple" Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'" />
<PackageReference Include="System.ComponentModel.Annotations" Condition="!$([MSBuild]::IsTargetFrameworkCompatible($(TargetFramework), 'netcoreapp3.1'))" />
Expand Down
2 changes: 1 addition & 1 deletion src/Polly.Core/PredicateBuilder.TResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Polly;
/// <typeparam name="TResult">The type of the result.</typeparam>
public partial class PredicateBuilder<TResult>
{
private readonly List<Predicate<Outcome<TResult>>> _predicates = new();
private readonly List<Predicate<Outcome<TResult>>> _predicates = [];

/// <summary>
/// Adds a predicate for handling exceptions of the specified type.
Expand Down
3 changes: 3 additions & 0 deletions src/Polly.Core/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ Polly.CircuitBreaker.BreakDurationGeneratorArguments.FailureCount.get -> int
Polly.CircuitBreaker.BreakDurationGeneratorArguments.FailureRate.get -> double
Polly.CircuitBreaker.CircuitBreakerStrategyOptions<TResult>.BreakDurationGenerator.get -> System.Func<Polly.CircuitBreaker.BreakDurationGeneratorArguments, System.Threading.Tasks.ValueTask<System.TimeSpan>>?
Polly.CircuitBreaker.CircuitBreakerStrategyOptions<TResult>.BreakDurationGenerator.set -> void
Polly.ResiliencePipelineBuilderBase.TimeProvider.get -> System.TimeProvider?
Polly.ResiliencePipelineBuilderBase.TimeProvider.set -> void
Polly.StrategyBuilderContext.TimeProvider.get -> System.TimeProvider!
4 changes: 2 additions & 2 deletions src/Polly.Core/Registry/ConfigureBuilderContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ internal ConfigureBuilderContext(TKey strategyKey, string builderName, string? b
/// </summary>
internal string? BuilderInstanceName { get; }

internal List<CancellationToken> ReloadTokens { get; } = new();
internal List<CancellationToken> ReloadTokens { get; } = [];

internal List<Action> DisposeCallbacks { get; } = new();
internal List<Action> DisposeCallbacks { get; } = [];

/// <summary>
/// Reloads the pipeline when <paramref name="cancellationToken"/> is canceled.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private Builder CreateBuilder()
builder.InstanceName = _instanceName;
_configure(builder, context);

var timeProvider = builder.TimeProvider;
var timeProvider = builder.TimeProviderInternal;
var telemetry = new ResilienceStrategyTelemetry(
new ResilienceTelemetrySource(builder.Name, builder.InstanceName, null),
builder.TelemetryListener);
Expand Down
19 changes: 8 additions & 11 deletions src/Polly.Core/ResiliencePipelineBuilderBase.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.ComponentModel;

using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using Polly.Telemetry;
Expand All @@ -19,7 +18,7 @@ namespace Polly;
public abstract class ResiliencePipelineBuilderBase
#pragma warning restore S1694 // An abstract class should have both abstract and concrete methods
{
private readonly List<Entry> _entries = new();
private readonly List<Entry> _entries = [];
private bool _used;

private protected ResiliencePipelineBuilderBase()
Expand Down Expand Up @@ -69,16 +68,12 @@ private protected ResiliencePipelineBuilderBase(ResiliencePipelineBuilderBase ot
public ResilienceContextPool? ContextPool { get; set; }

/// <summary>
/// Gets or sets a <see cref="System.TimeProvider"/> that is used by strategies that work with time.
/// Gets or sets a <see cref="TimeProvider"/> that is used by strategies that work with time.
/// </summary>
/// <remarks>
/// This property is internal until we switch to official System.TimeProvider.
/// </remarks>
/// <value>
/// The default value is <see cref="TimeProvider.System"/>.
/// The default value is <see langword="null"/> and unless set, <see cref="TimeProvider.System"/> will be used.
/// </value>
[Required]
internal TimeProvider TimeProvider { get; set; } = TimeProvider.System;
public TimeProvider? TimeProvider { get; set; }

/// <summary>
/// Gets or sets the <see cref="Polly.Telemetry.TelemetryListener"/> that is used by Polly to report resilience events.
Expand All @@ -92,6 +87,8 @@ private protected ResiliencePipelineBuilderBase(ResiliencePipelineBuilderBase ot
[EditorBrowsable(EditorBrowsableState.Never)]
public TelemetryListener? TelemetryListener { get; set; }

internal TimeProvider TimeProviderInternal => TimeProvider ?? TimeProvider.System;

/// <summary>
/// Gets the validator that is used for the validation.
/// </summary>
Expand Down Expand Up @@ -133,13 +130,13 @@ internal PipelineComponent BuildPipelineComponent()

var source = new ResilienceTelemetrySource(Name, InstanceName, null);

return PipelineComponentFactory.CreateComposite(components, new ResilienceStrategyTelemetry(source, TelemetryListener), TimeProvider);
return PipelineComponentFactory.CreateComposite(components, new ResilienceStrategyTelemetry(source, TelemetryListener), TimeProviderInternal);
}

private PipelineComponent CreateComponent(Entry entry)
{
var source = new ResilienceTelemetrySource(Name, InstanceName, entry.Options.Name);
var context = new StrategyBuilderContext(new ResilienceStrategyTelemetry(source, TelemetryListener), TimeProvider);
var context = new StrategyBuilderContext(new ResilienceStrategyTelemetry(source, TelemetryListener), TimeProviderInternal);

var strategy = entry.Factory(context);
strategy.Options = entry.Options;
Expand Down
2 changes: 1 addition & 1 deletion src/Polly.Core/StrategyBuilderContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ internal StrategyBuilderContext(ResilienceStrategyTelemetry telemetry, TimeProvi
/// <summary>
/// Gets the <see cref="TimeProvider"/> used by this strategy.
/// </summary>
internal TimeProvider TimeProvider { get; }
public TimeProvider TimeProvider { get; }
}