-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #172 from zeebe-io/zell-retry
Add new SendWithRetry API method
- Loading branch information
Showing
23 changed files
with
455 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
167 changes: 167 additions & 0 deletions
167
Client.UnitTests/TransientGrpcErrorRetryStrategyTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Net.WebSockets; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Grpc.Core; | ||
using NUnit.Framework; | ||
using Zeebe.Client.Impl.Misc; | ||
|
||
namespace Zeebe.Client | ||
{ | ||
[TestFixture] | ||
public class TransientGrpcErrorRetryStrategyTest | ||
{ | ||
[Test] | ||
public async Task ShouldRetryOnResourceExhaustedException() | ||
{ | ||
// given | ||
int retries = 0; | ||
var strategy = new TransientGrpcErrorRetryStrategy(retry => TimeSpan.Zero); | ||
|
||
// when | ||
var result = await strategy.DoWithRetry(() => | ||
{ | ||
if (retries == 3) | ||
{ | ||
return Task.FromResult(retries); | ||
} | ||
|
||
retries++; | ||
throw new RpcException(new Status(StatusCode.ResourceExhausted, "resourceExhausted")); | ||
}); | ||
|
||
// then | ||
Assert.AreEqual(3, result); | ||
} | ||
|
||
[Test] | ||
public async Task ShouldRetryOnUnavailableException() | ||
{ | ||
// given | ||
int retries = 0; | ||
var strategy = new TransientGrpcErrorRetryStrategy(retry => TimeSpan.Zero); | ||
|
||
// when | ||
var result = await strategy.DoWithRetry(() => | ||
{ | ||
if (retries == 3) | ||
{ | ||
return Task.FromResult(retries); | ||
} | ||
|
||
retries++; | ||
throw new RpcException(new Status(StatusCode.Unavailable, "resourceExhausted")); | ||
}); | ||
|
||
// then | ||
Assert.AreEqual(3, result); | ||
} | ||
|
||
[Test] | ||
public async Task ShouldIncrementRetriesOnWaitTimeProvider() | ||
{ | ||
// given | ||
var retries = 0; | ||
var values = new List<int>(); | ||
var strategy = new TransientGrpcErrorRetryStrategy(retry => | ||
{ | ||
values.Add(retry); | ||
return TimeSpan.Zero; | ||
}); | ||
|
||
// when | ||
var result = await strategy.DoWithRetry(() => | ||
{ | ||
if (retries == 3) | ||
{ | ||
return Task.FromResult(retries); | ||
} | ||
|
||
retries++; | ||
throw new RpcException(new Status(StatusCode.ResourceExhausted, "resourceExhausted")); | ||
}); | ||
|
||
// then | ||
Assert.AreEqual(3, result); | ||
CollectionAssert.AreEqual(new List<int> { 1, 2, 3 }, values); | ||
} | ||
|
||
[Test] | ||
public void ShouldWaitProvidedTime() | ||
{ | ||
// given | ||
var retries = 0; | ||
var countdownEvent = new CountdownEvent(2); | ||
var strategy = new TransientGrpcErrorRetryStrategy(retry => TimeSpan.FromSeconds(1)); | ||
|
||
// when | ||
strategy.DoWithRetry(() => | ||
{ | ||
countdownEvent.Signal(); | ||
if (retries == 3) | ||
{ | ||
return Task.FromResult(retries); | ||
} | ||
|
||
retries++; | ||
throw new RpcException(new Status(StatusCode.ResourceExhausted, "resourceExhausted")); | ||
}); | ||
countdownEvent.Wait(TimeSpan.FromMilliseconds(10)); | ||
|
||
// then | ||
Assert.AreEqual(countdownEvent.CurrentCount, 1); | ||
Assert.AreEqual(retries, 1); | ||
} | ||
|
||
[Test] | ||
public void ShouldNotRetryOnOtherRpcException() | ||
{ | ||
// given | ||
int retries = 0; | ||
var strategy = new TransientGrpcErrorRetryStrategy(retry => TimeSpan.Zero); | ||
|
||
// when | ||
var resultTask = strategy.DoWithRetry(() => | ||
{ | ||
if (retries == 3) | ||
{ | ||
return Task.FromResult(retries); | ||
} | ||
|
||
retries++; | ||
throw new RpcException(new Status(StatusCode.Unknown, "idk")); | ||
}); | ||
|
||
// then | ||
var aggregateException = Assert.Throws<AggregateException>(() => resultTask.Wait()); | ||
var rpcException = (RpcException) aggregateException.InnerExceptions[0]; | ||
Assert.AreEqual(StatusCode.Unknown, rpcException.Status.StatusCode); | ||
} | ||
|
||
[Test] | ||
public void ShouldNotRetryOnOtherException() | ||
{ | ||
// given | ||
int retries = 0; | ||
var strategy = new TransientGrpcErrorRetryStrategy(retry => TimeSpan.Zero); | ||
|
||
// when | ||
var resultTask = strategy.DoWithRetry(() => | ||
{ | ||
if (retries == 3) | ||
{ | ||
return Task.FromResult(retries); | ||
} | ||
|
||
retries++; | ||
throw new Exception("exception"); | ||
}); | ||
|
||
// then | ||
var aggregateException = Assert.Throws<AggregateException>(() => resultTask.Wait()); | ||
var exception = aggregateException.InnerExceptions[0]; | ||
Assert.AreEqual("exception", exception.Message); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
|
||
namespace Zeebe.Client.Api.Misc | ||
{ | ||
public interface IAsyncRetryStrategy | ||
{ | ||
/// <summary> | ||
/// Runs the given asynchronous action asynchronously and retries it if it fails. | ||
/// When and how it is retried is depended of the implementation. | ||
/// </summary> | ||
/// <param name="action">the action which should be run and retried</param> | ||
/// <typeparam name="TResult">the result type</typeparam> | ||
/// <returns>the result of the action</returns> | ||
Task<TResult> DoWithRetry<TResult>(Func<Task<TResult>> action); | ||
} | ||
} |
Oops, something went wrong.