Skip to content

Commit

Permalink
Polish retry logic
Browse files Browse the repository at this point in the history
  • Loading branch information
cyanfish committed Dec 27, 2023
1 parent ff33ad1 commit 0e573a7
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 16 deletions.
10 changes: 2 additions & 8 deletions GrpcDotNetNamedPipes.PerfTests/GrpcPerformanceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,11 @@ public void UnarySequentialChannelsPerformance(ChannelContextFactory factory)
_testOutputHelper.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
}

[Theory(Timeout = Timeout)]
// Windows seems to stall when 32+ threads try to connect to a named pipe at once
[Theory(Timeout = Timeout, Skip = "named pipes fail with too many parallel channels")]
[ClassData(typeof(MultiChannelWithAspNetClassData))]
public async Task UnaryParallelChannelsPerformance(ChannelContextFactory factory)
{
#if NET8_0_OR_GREATER
if (factory is AspNetPipeContextFactory)
{
_testOutputHelper.WriteLine("Skipped (ASP.NET named pipes fail with too many parallel channels)");
return;
}
#endif
using var ctx = factory.Create();
var stopwatch = Stopwatch.StartNew();
var tasks = new Task[1_000];
Expand Down
17 changes: 9 additions & 8 deletions GrpcDotNetNamedPipes/Internal/ClientConnectionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,29 +109,30 @@ private async Task ConnectPipeWithRetries()
// In theory .Connect is supposed to have a timeout and not need retries, but it turns
// out that in practice sometimes it does.
var elapsed = Stopwatch.StartNew();
int TimeLeft() => Math.Max(_connectionTimeout - (int) elapsed.ElapsedMilliseconds, 0);
var fallback = 100;
while (true)
{
try
{
await _connectLock.Take();
var waitTime = _connectionTimeout == -1
? -1
: Math.Min(1000, Math.Max(_connectionTimeout - (int) elapsed.ElapsedMilliseconds, 0));
var waitTime = _connectionTimeout == -1 ? 1000 : Math.Min(1000, TimeLeft());
await _pipeStream.ConnectAsync(waitTime).ConfigureAwait(false);
_connectLock.Release();
break;
}
catch (Exception ex) when (ex is TimeoutException or IOException)
catch (Exception ex)
{
_connectLock.Release();
if (_connectionTimeout != -1 && elapsed.ElapsedMilliseconds > _connectionTimeout)
if (ex is not (TimeoutException or IOException))
{
throw;
}
if (_connectionTimeout != -1 && TimeLeft() == 0)
{
throw;
}
var delayTime = _connectionTimeout == -1
? fallback
: Math.Min(fallback, Math.Max(_connectionTimeout - (int) elapsed.ElapsedMilliseconds, 0));
var delayTime = _connectionTimeout == -1 ? fallback : Math.Min(fallback, TimeLeft());
await Task.Delay(delayTime);
fallback = Math.Min(fallback * 2, 1000);
}
Expand Down

0 comments on commit 0e573a7

Please sign in to comment.