[repo] Update dotnet format ci job (#4881)

Co-authored-by: Reiley Yang <reyang@microsoft.com>
Co-authored-by: Utkarsh Umesan Pillai <66651184+utpilla@users.noreply.github.com>
Co-authored-by: Mikel Blanchard <mblanchard@macrosssoftware.com>
This commit is contained in:
Tom Biddulph 2023-11-01 19:20:52 +00:00 committed by GitHub
parent ff9912f87a
commit 2de73b2c12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 255 additions and 260 deletions

View File

@ -23,8 +23,5 @@ jobs:
- name: Setup dotnet
uses: actions/setup-dotnet@v3
- name: Install format tool
run: dotnet tool install -g dotnet-format
- name: dotnet format
run: dotnet-format --folder --check
run: dotnet format OpenTelemetry.sln --verify-no-changes

View File

@ -27,11 +27,11 @@ namespace OpenTelemetry.Logs;
/// Contains extension methods for the <see cref="LoggerProviderBuilder"/> class.
/// </summary>
#if EXPOSE_EXPERIMENTAL_FEATURES
public
public
#else
internal
#endif
static class OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions
static class OpenTelemetryDependencyInjectionLoggerProviderBuilderExtensions
{
#if EXPOSE_EXPERIMENTAL_FEATURES
/// <summary>
@ -59,9 +59,9 @@ namespace OpenTelemetry.Logs;
#endif
public static LoggerProviderBuilder AddInstrumentation<
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this LoggerProviderBuilder loggerProviderBuilder)
T>(this LoggerProviderBuilder loggerProviderBuilder)
where T : class
{
loggerProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());

View File

@ -23,11 +23,11 @@ namespace OpenTelemetry.Logs;
/// Extension methods for setting up OpenTelemetry logging services in an <see cref="IServiceCollection" />.
/// </summary>
#if EXPOSE_EXPERIMENTAL_FEATURES
public
public
#else
internal
#endif
static class OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions
static class OpenTelemetryDependencyInjectionLoggingServiceCollectionExtensions
{
#if EXPOSE_EXPERIMENTAL_FEATURES
/// <summary>

View File

@ -40,9 +40,9 @@ public static class OpenTelemetryDependencyInjectionMeterProviderBuilderExtensio
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddInstrumentation<
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this MeterProviderBuilder meterProviderBuilder)
T>(this MeterProviderBuilder meterProviderBuilder)
where T : class
{
meterProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());

View File

@ -40,9 +40,9 @@ public static class OpenTelemetryDependencyInjectionTracerProviderBuilderExtensi
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder AddInstrumentation<
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this TracerProviderBuilder tracerProviderBuilder)
T>(this TracerProviderBuilder tracerProviderBuilder)
where T : class
{
tracerProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());

View File

@ -67,12 +67,12 @@ internal static class OtlpRetry
public static bool TryGetHttpRetryResult(HttpStatusCode statusCode, DateTime? deadline, HttpResponseHeaders responseHeaders, int retryDelayMilliseconds, out RetryResult retryResult)
{
return OtlpRetry.TryGetRetryResult(statusCode, IsHttpStatusCodeRetryable, deadline, responseHeaders, TryGetHttpRetryDelay, retryDelayMilliseconds, out retryResult);
return TryGetRetryResult(statusCode, IsHttpStatusCodeRetryable, deadline, responseHeaders, TryGetHttpRetryDelay, retryDelayMilliseconds, out retryResult);
}
public static bool TryGetGrpcRetryResult(StatusCode statusCode, DateTime? deadline, Metadata trailers, int retryDelayMilliseconds, out RetryResult retryResult)
{
return OtlpRetry.TryGetRetryResult(statusCode, IsGrpcStatusCodeRetryable, deadline, trailers, TryGetGrpcRetryDelay, retryDelayMilliseconds, out retryResult);
return TryGetRetryResult(statusCode, IsGrpcStatusCodeRetryable, deadline, trailers, TryGetGrpcRetryDelay, retryDelayMilliseconds, out retryResult);
}
private static bool TryGetRetryResult<TStatusCode, TCarrier>(TStatusCode statusCode, Func<TStatusCode, bool, bool> isRetryable, DateTime? deadline, TCarrier carrier, Func<TStatusCode, TCarrier, TimeSpan?> throttleGetter, int nextRetryDelayMilliseconds, out RetryResult retryResult)

View File

@ -165,9 +165,9 @@ internal
#endif
public static LoggerProviderBuilder AddProcessor<
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this LoggerProviderBuilder loggerProviderBuilder)
T>(this LoggerProviderBuilder loggerProviderBuilder)
where T : BaseProcessor<LogRecord>
{
loggerProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());

View File

@ -64,9 +64,9 @@ public static class MeterProviderBuilderExtensions
/// <returns>The supplied <see cref="MeterProviderBuilder"/> for chaining.</returns>
public static MeterProviderBuilder AddReader<
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this MeterProviderBuilder meterProviderBuilder)
T>(this MeterProviderBuilder meterProviderBuilder)
where T : MetricReader
{
meterProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());

View File

@ -83,9 +83,9 @@ public static class TracerProviderBuilderExtensions
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder SetSampler<
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this TracerProviderBuilder tracerProviderBuilder)
T>(this TracerProviderBuilder tracerProviderBuilder)
where T : Sampler
{
tracerProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());
@ -203,9 +203,9 @@ public static class TracerProviderBuilderExtensions
/// <returns>The supplied <see cref="TracerProviderBuilder"/> for chaining.</returns>
public static TracerProviderBuilder AddProcessor<
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(this TracerProviderBuilder tracerProviderBuilder)
T>(this TracerProviderBuilder tracerProviderBuilder)
where T : BaseProcessor<Activity>
{
tracerProviderBuilder.ConfigureServices(services => services.TryAddSingleton<T>());

View File

@ -19,90 +19,89 @@
using System.Runtime.CompilerServices;
using OpenTelemetry.Trace;
namespace OpenTelemetry.Exporter
namespace OpenTelemetry.Exporter;
internal static class PeerServiceResolver
{
internal static class PeerServiceResolver
private static readonly Dictionary<string, int> PeerServiceKeyResolutionDictionary = new(StringComparer.OrdinalIgnoreCase)
{
private static readonly Dictionary<string, int> PeerServiceKeyResolutionDictionary = new(StringComparer.OrdinalIgnoreCase)
[SemanticConventions.AttributePeerService] = 0, // priority 0 (highest).
["peer.hostname"] = 1,
["peer.address"] = 1,
[SemanticConventions.AttributeHttpHost] = 2, // peer.service for Http.
[SemanticConventions.AttributeDbInstance] = 2, // peer.service for Redis.
};
public interface IPeerServiceState
{
string? PeerService { get; set; }
int? PeerServicePriority { get; set; }
string? HostName { get; set; }
string? IpAddress { get; set; }
long Port { get; set; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InspectTag<T>(ref T state, string key, string? value)
where T : struct, IPeerServiceState
{
if (PeerServiceKeyResolutionDictionary.TryGetValue(key, out int priority)
&& (state.PeerService == null || priority < state.PeerServicePriority))
{
[SemanticConventions.AttributePeerService] = 0, // priority 0 (highest).
["peer.hostname"] = 1,
["peer.address"] = 1,
[SemanticConventions.AttributeHttpHost] = 2, // peer.service for Http.
[SemanticConventions.AttributeDbInstance] = 2, // peer.service for Redis.
};
public interface IPeerServiceState
{
string? PeerService { get; set; }
int? PeerServicePriority { get; set; }
string? HostName { get; set; }
string? IpAddress { get; set; }
long Port { get; set; }
state.PeerService = value;
state.PeerServicePriority = priority;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InspectTag<T>(ref T state, string key, string? value)
where T : struct, IPeerServiceState
else if (key == SemanticConventions.AttributeNetPeerName)
{
if (PeerServiceKeyResolutionDictionary.TryGetValue(key, out int priority)
&& (state.PeerService == null || priority < state.PeerServicePriority))
{
state.PeerService = value;
state.PeerServicePriority = priority;
}
else if (key == SemanticConventions.AttributeNetPeerName)
{
state.HostName = value;
}
else if (key == SemanticConventions.AttributeNetPeerIp)
{
state.IpAddress = value;
}
else if (key == SemanticConventions.AttributeNetPeerPort && long.TryParse(value, out var port))
{
state.Port = port;
}
state.HostName = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InspectTag<T>(ref T state, string key, long value)
where T : struct, IPeerServiceState
else if (key == SemanticConventions.AttributeNetPeerIp)
{
if (key == SemanticConventions.AttributeNetPeerPort)
{
state.Port = value;
}
state.IpAddress = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Resolve<T>(ref T state, out string? peerServiceName, out bool addAsTag)
where T : struct, IPeerServiceState
else if (key == SemanticConventions.AttributeNetPeerPort && long.TryParse(value, out var port))
{
peerServiceName = state.PeerService;
state.Port = port;
}
}
// If priority = 0 that means peer.service was included in tags
addAsTag = state.PeerServicePriority != 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InspectTag<T>(ref T state, string key, long value)
where T : struct, IPeerServiceState
{
if (key == SemanticConventions.AttributeNetPeerPort)
{
state.Port = value;
}
}
if (addAsTag)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Resolve<T>(ref T state, out string? peerServiceName, out bool addAsTag)
where T : struct, IPeerServiceState
{
peerServiceName = state.PeerService;
// If priority = 0 that means peer.service was included in tags
addAsTag = state.PeerServicePriority != 0;
if (addAsTag)
{
var hostNameOrIpAddress = state.HostName ?? state.IpAddress;
// peer.service has not already been included, but net.peer.name/ip and optionally net.peer.port are present
if (hostNameOrIpAddress != null)
{
var hostNameOrIpAddress = state.HostName ?? state.IpAddress;
// peer.service has not already been included, but net.peer.name/ip and optionally net.peer.port are present
if (hostNameOrIpAddress != null)
{
peerServiceName = state.Port == default
? hostNameOrIpAddress
: $"{hostNameOrIpAddress}:{state.Port}";
}
else if (state.PeerService != null)
{
peerServiceName = state.PeerService;
}
peerServiceName = state.Port == default
? hostNameOrIpAddress
: $"{hostNameOrIpAddress}:{state.Port}";
}
else if (state.PeerService != null)
{
peerServiceName = state.PeerService;
}
}
}

View File

@ -60,7 +60,7 @@ public class OtlpMetricsExporterTests : Http2UnencryptedSupportTests
void CheckMetricReaderDefaults()
{
var bindingFlags = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance;
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
var metricReader = typeof(MetricReader)
.Assembly

View File

@ -19,198 +19,197 @@ using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Xunit;
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.Tests
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.Tests;
public class OtlpRetryTests
{
public class OtlpRetryTests
public static IEnumerable<object[]> GrpcRetryTestData => GrpcRetryTestCase.GetTestCases();
[Theory]
[MemberData(nameof(GrpcRetryTestData))]
public void TryGetGrpcRetryResultTest(GrpcRetryTestCase testCase)
{
public static IEnumerable<object[]> GrpcRetryTestData => GrpcRetryTestCase.GetTestCases();
var attempts = 0;
var nextRetryDelayMilliseconds = OtlpRetry.InitialBackoffMilliseconds;
[Theory]
[MemberData(nameof(GrpcRetryTestData))]
public void TryGetGrpcRetryResultTest(GrpcRetryTestCase testCase)
foreach (var retryAttempt in testCase.RetryAttempts)
{
var attempts = 0;
var nextRetryDelayMilliseconds = OtlpRetry.InitialBackoffMilliseconds;
++attempts;
var statusCode = retryAttempt.RpcException.StatusCode;
var deadline = retryAttempt.CallOptions.Deadline;
var trailers = retryAttempt.RpcException.Trailers;
var success = OtlpRetry.TryGetGrpcRetryResult(statusCode, deadline, trailers, nextRetryDelayMilliseconds, out var retryResult);
foreach (var retryAttempt in testCase.RetryAttempts)
Assert.Equal(retryAttempt.ExpectedSuccess, success);
if (!success)
{
++attempts;
var statusCode = retryAttempt.RpcException.StatusCode;
var deadline = retryAttempt.CallOptions.Deadline;
var trailers = retryAttempt.RpcException.Trailers;
var success = OtlpRetry.TryGetGrpcRetryResult(statusCode, deadline, trailers, nextRetryDelayMilliseconds, out var retryResult);
Assert.Equal(retryAttempt.ExpectedSuccess, success);
if (!success)
{
Assert.Equal(testCase.ExpectedRetryAttempts, attempts);
break;
}
if (retryResult.Throttled)
{
Assert.Equal(retryAttempt.ThrottleDelay, retryResult.RetryDelay);
}
else
{
Assert.True(retryResult.RetryDelay >= TimeSpan.Zero);
Assert.True(retryResult.RetryDelay < TimeSpan.FromMilliseconds(nextRetryDelayMilliseconds));
}
Assert.Equal(retryAttempt.ExpectedNextRetryDelayMilliseconds, retryResult.NextRetryDelayMilliseconds);
nextRetryDelayMilliseconds = retryResult.NextRetryDelayMilliseconds;
Assert.Equal(testCase.ExpectedRetryAttempts, attempts);
break;
}
Assert.Equal(testCase.ExpectedRetryAttempts, attempts);
if (retryResult.Throttled)
{
Assert.Equal(retryAttempt.ThrottleDelay, retryResult.RetryDelay);
}
else
{
Assert.True(retryResult.RetryDelay >= TimeSpan.Zero);
Assert.True(retryResult.RetryDelay < TimeSpan.FromMilliseconds(nextRetryDelayMilliseconds));
}
Assert.Equal(retryAttempt.ExpectedNextRetryDelayMilliseconds, retryResult.NextRetryDelayMilliseconds);
nextRetryDelayMilliseconds = retryResult.NextRetryDelayMilliseconds;
}
public class GrpcRetryTestCase
Assert.Equal(testCase.ExpectedRetryAttempts, attempts);
}
public class GrpcRetryTestCase
{
public int ExpectedRetryAttempts;
public GrpcRetryAttempt[] RetryAttempts;
private string testRunnerName;
private GrpcRetryTestCase(string testRunnerName, GrpcRetryAttempt[] retryAttempts, int expectedRetryAttempts = 1)
{
public int ExpectedRetryAttempts;
public GrpcRetryAttempt[] RetryAttempts;
this.ExpectedRetryAttempts = expectedRetryAttempts;
this.RetryAttempts = retryAttempts;
this.testRunnerName = testRunnerName;
}
private string testRunnerName;
public static IEnumerable<object[]> GetTestCases()
{
yield return new[] { new GrpcRetryTestCase("Cancelled", new GrpcRetryAttempt[] { new(StatusCode.Cancelled) }) };
yield return new[] { new GrpcRetryTestCase("DeadlineExceeded", new GrpcRetryAttempt[] { new(StatusCode.DeadlineExceeded) }) };
yield return new[] { new GrpcRetryTestCase("Aborted", new GrpcRetryAttempt[] { new(StatusCode.Aborted) }) };
yield return new[] { new GrpcRetryTestCase("OutOfRange", new GrpcRetryAttempt[] { new(StatusCode.OutOfRange) }) };
yield return new[] { new GrpcRetryTestCase("DataLoss", new GrpcRetryAttempt[] { new(StatusCode.DataLoss) }) };
yield return new[] { new GrpcRetryTestCase("Unavailable", new GrpcRetryAttempt[] { new(StatusCode.Unavailable) }) };
private GrpcRetryTestCase(string testRunnerName, GrpcRetryAttempt[] retryAttempts, int expectedRetryAttempts = 1)
yield return new[] { new GrpcRetryTestCase("OK", new GrpcRetryAttempt[] { new(StatusCode.OK, expectedSuccess: false) }) };
yield return new[] { new GrpcRetryTestCase("PermissionDenied", new GrpcRetryAttempt[] { new(StatusCode.PermissionDenied, expectedSuccess: false) }) };
yield return new[] { new GrpcRetryTestCase("Unknown", new GrpcRetryAttempt[] { new(StatusCode.Unknown, expectedSuccess: false) }) };
yield return new[] { new GrpcRetryTestCase("ResourceExhausted w/o RetryInfo", new GrpcRetryAttempt[] { new(StatusCode.ResourceExhausted, expectedSuccess: false) }) };
yield return new[] { new GrpcRetryTestCase("ResourceExhausted w/ RetryInfo", new GrpcRetryAttempt[] { new(StatusCode.ResourceExhausted, throttleDelay: new Duration { Seconds = 2 }, expectedNextRetryDelayMilliseconds: 3000) }) };
yield return new[] { new GrpcRetryTestCase("Unavailable w/ RetryInfo", new GrpcRetryAttempt[] { new(StatusCode.Unavailable, throttleDelay: Duration.FromTimeSpan(TimeSpan.FromMilliseconds(2000)), expectedNextRetryDelayMilliseconds: 3000) }) };
yield return new[] { new GrpcRetryTestCase("Expired deadline", new GrpcRetryAttempt[] { new(StatusCode.Unavailable, deadlineExceeded: true, expectedSuccess: false) }) };
yield return new[]
{
this.ExpectedRetryAttempts = expectedRetryAttempts;
this.RetryAttempts = retryAttempts;
this.testRunnerName = testRunnerName;
}
new GrpcRetryTestCase(
"Exponential backoff",
new GrpcRetryAttempt[]
{
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3375),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
},
expectedRetryAttempts: 5),
};
public static IEnumerable<object[]> GetTestCases()
yield return new[]
{
yield return new[] { new GrpcRetryTestCase("Cancelled", new GrpcRetryAttempt[] { new(StatusCode.Cancelled) }) };
yield return new[] { new GrpcRetryTestCase("DeadlineExceeded", new GrpcRetryAttempt[] { new(StatusCode.DeadlineExceeded) }) };
yield return new[] { new GrpcRetryTestCase("Aborted", new GrpcRetryAttempt[] { new(StatusCode.Aborted) }) };
yield return new[] { new GrpcRetryTestCase("OutOfRange", new GrpcRetryAttempt[] { new(StatusCode.OutOfRange) }) };
yield return new[] { new GrpcRetryTestCase("DataLoss", new GrpcRetryAttempt[] { new(StatusCode.DataLoss) }) };
yield return new[] { new GrpcRetryTestCase("Unavailable", new GrpcRetryAttempt[] { new(StatusCode.Unavailable) }) };
new GrpcRetryTestCase(
"Retry until non-retryable status code encountered",
new GrpcRetryAttempt[]
{
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3375),
new(StatusCode.PermissionDenied, expectedSuccess: false),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
},
expectedRetryAttempts: 4),
};
yield return new[] { new GrpcRetryTestCase("OK", new GrpcRetryAttempt[] { new(StatusCode.OK, expectedSuccess: false) }) };
yield return new[] { new GrpcRetryTestCase("PermissionDenied", new GrpcRetryAttempt[] { new(StatusCode.PermissionDenied, expectedSuccess: false) }) };
yield return new[] { new GrpcRetryTestCase("Unknown", new GrpcRetryAttempt[] { new(StatusCode.Unknown, expectedSuccess: false) }) };
yield return new[] { new GrpcRetryTestCase("ResourceExhausted w/o RetryInfo", new GrpcRetryAttempt[] { new(StatusCode.ResourceExhausted, expectedSuccess: false) }) };
yield return new[] { new GrpcRetryTestCase("ResourceExhausted w/ RetryInfo", new GrpcRetryAttempt[] { new(StatusCode.ResourceExhausted, throttleDelay: new Duration { Seconds = 2 }, expectedNextRetryDelayMilliseconds: 3000) }) };
yield return new[] { new GrpcRetryTestCase("Unavailable w/ RetryInfo", new GrpcRetryAttempt[] { new(StatusCode.Unavailable, throttleDelay: Duration.FromTimeSpan(TimeSpan.FromMilliseconds(2000)), expectedNextRetryDelayMilliseconds: 3000) }) };
yield return new[] { new GrpcRetryTestCase("Expired deadline", new GrpcRetryAttempt[] { new(StatusCode.Unavailable, deadlineExceeded: true, expectedSuccess: false) }) };
yield return new[]
{
new GrpcRetryTestCase(
"Exponential backoff",
new GrpcRetryAttempt[]
{
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3375),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
},
expectedRetryAttempts: 5),
};
yield return new[]
{
new GrpcRetryTestCase(
"Retry until non-retryable status code encountered",
new GrpcRetryAttempt[]
{
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3375),
new(StatusCode.PermissionDenied, expectedSuccess: false),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
},
expectedRetryAttempts: 4),
};
// Test throttling affects exponential backoff.
yield return new[]
{
new GrpcRetryTestCase(
"Exponential backoff after throttling",
new GrpcRetryAttempt[]
{
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
new(StatusCode.Unavailable, throttleDelay: Duration.FromTimeSpan(TimeSpan.FromMilliseconds(500)), expectedNextRetryDelayMilliseconds: 750),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1125),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1688),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2532),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3798),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
},
expectedRetryAttempts: 9),
};
yield return new[]
{
new GrpcRetryTestCase(
"Ridiculous throttling delay",
new GrpcRetryAttempt[]
{
new(StatusCode.Unavailable, throttleDelay: Duration.FromTimeSpan(TimeSpan.FromDays(3000000)), expectedNextRetryDelayMilliseconds: 5000),
}),
};
}
public override string ToString()
// Test throttling affects exponential backoff.
yield return new[]
{
return this.testRunnerName;
}
new GrpcRetryTestCase(
"Exponential backoff after throttling",
new GrpcRetryAttempt[]
{
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1500),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2250),
new(StatusCode.Unavailable, throttleDelay: Duration.FromTimeSpan(TimeSpan.FromMilliseconds(500)), expectedNextRetryDelayMilliseconds: 750),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1125),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 1688),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 2532),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 3798),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
new(StatusCode.Unavailable, expectedNextRetryDelayMilliseconds: 5000),
},
expectedRetryAttempts: 9),
};
private static Metadata GenerateTrailers(Duration throttleDelay)
yield return new[]
{
var metadata = new Metadata();
new GrpcRetryTestCase(
"Ridiculous throttling delay",
new GrpcRetryAttempt[]
{
new(StatusCode.Unavailable, throttleDelay: Duration.FromTimeSpan(TimeSpan.FromDays(3000000)), expectedNextRetryDelayMilliseconds: 5000),
}),
};
}
var retryInfo = new Google.Rpc.RetryInfo();
retryInfo.RetryDelay = throttleDelay;
public override string ToString()
{
return this.testRunnerName;
}
var status = new Google.Rpc.Status();
status.Details.Add(Any.Pack(retryInfo));
private static Metadata GenerateTrailers(Duration throttleDelay)
{
var metadata = new Metadata();
var stream = new MemoryStream();
status.WriteTo(stream);
var retryInfo = new Google.Rpc.RetryInfo();
retryInfo.RetryDelay = throttleDelay;
metadata.Add(OtlpRetry.GrpcStatusDetailsHeader, stream.ToArray());
return metadata;
}
var status = new Google.Rpc.Status();
status.Details.Add(Any.Pack(retryInfo));
public struct GrpcRetryAttempt
var stream = new MemoryStream();
status.WriteTo(stream);
metadata.Add(OtlpRetry.GrpcStatusDetailsHeader, stream.ToArray());
return metadata;
}
public struct GrpcRetryAttempt
{
public RpcException RpcException;
public CallOptions CallOptions;
public TimeSpan? ThrottleDelay;
public int? ExpectedNextRetryDelayMilliseconds;
public bool ExpectedSuccess;
public GrpcRetryAttempt(
StatusCode statusCode,
bool deadlineExceeded = false,
Duration throttleDelay = null,
int expectedNextRetryDelayMilliseconds = 1500,
bool expectedSuccess = true)
{
public RpcException RpcException;
public CallOptions CallOptions;
public TimeSpan? ThrottleDelay;
public int? ExpectedNextRetryDelayMilliseconds;
public bool ExpectedSuccess;
var status = new Status(statusCode, "Error");
this.RpcException = throttleDelay != null
? new RpcException(status, GenerateTrailers(throttleDelay))
: new RpcException(status);
public GrpcRetryAttempt(
StatusCode statusCode,
bool deadlineExceeded = false,
Duration throttleDelay = null,
int expectedNextRetryDelayMilliseconds = 1500,
bool expectedSuccess = true)
{
var status = new Status(statusCode, "Error");
this.RpcException = throttleDelay != null
? new RpcException(status, GenerateTrailers(throttleDelay))
: new RpcException(status);
this.CallOptions = deadlineExceeded ? new CallOptions(deadline: DateTime.UtcNow.AddSeconds(-1)) : default;
this.CallOptions = deadlineExceeded ? new CallOptions(deadline: DateTime.UtcNow.AddSeconds(-1)) : default;
this.ThrottleDelay = throttleDelay != null ? throttleDelay.ToTimeSpan() : null;
this.ThrottleDelay = throttleDelay != null ? throttleDelay.ToTimeSpan() : null;
this.ExpectedNextRetryDelayMilliseconds = expectedNextRetryDelayMilliseconds;
this.ExpectedNextRetryDelayMilliseconds = expectedNextRetryDelayMilliseconds;
this.ExpectedSuccess = expectedSuccess;
}
this.ExpectedSuccess = expectedSuccess;
}
}
}

View File

@ -60,7 +60,7 @@ public class W3CTraceContextTests : IDisposable
// disabling due to failing dotnet-format
// TODO: investigate why dotnet-format fails.
#pragma warning disable SA1008 // Opening parenthesis should be spaced correctly
app.MapPost("/", async([FromBody] Data[] data) =>
app.MapPost("/", async ([FromBody] Data[] data) =>
{
var result = string.Empty;
if (data != null)