Skip to content

Commit

Permalink
Add Assert method to validate the result and retry
Browse files Browse the repository at this point in the history
  • Loading branch information
jerviscui committed Feb 16, 2023
1 parent d0f9d55 commit 932540d
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 15 deletions.
63 changes: 63 additions & 0 deletions src/RetryCore/AsyncRetryTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,22 @@ public IAsyncRetriable OnFailureAsync(Func<RetryResult, int, Task> failureAction

return this;
}

/// <inheritdoc />
public IAsyncRetriable Assert(Func<RetryResult, bool> condition)
{
_retryTask = _retryTask.Assert(condition);

return this;
}

/// <inheritdoc />
public IAsyncRetriable Assert(Func<RetryResult, Task<bool>> condition)
{
_retryTask = _retryTask.Assert(condition);

return this;
}
}

/// <summary>
Expand Down Expand Up @@ -156,6 +172,10 @@ public AsyncRetryTask(Func<Task<T>> function, RetryOptions retryOptions, Type[]

private readonly List<Delegate> _failureActions;

private Func<RetryResult<T>, bool>? _condition;

private Func<RetryResult<T>, Task<bool>>? _conditionTask;

private CancellationToken _cancellationToken;

/// <inheritdoc />
Expand Down Expand Up @@ -253,6 +273,24 @@ public IAsyncRetriable<T> OnFailureAsync(Func<RetryResult<T>, int, Task> failure
return this;
}

/// <inheritdoc />
public IAsyncRetriable<T> Assert(Func<RetryResult<T>, bool> condition)
{
_condition = condition;
_conditionTask = null;

return this;
}

/// <inheritdoc />
public IAsyncRetriable<T> Assert(Func<RetryResult<T>, Task<bool>> condition)
{
_conditionTask = condition;
_condition = null;

return this;
}

private async Task<RetryResult<T>> TryImplAsync()
{
//TraceSource.TraceVerbose("Starting trying with max try time {0} and max try count {1}.",
Expand Down Expand Up @@ -307,6 +345,20 @@ private async Task<RetryResult<T>> TryImplAsync()
break;
}

//assert
try
{
if (await AssertThenRetry(result))
{
continue;
}
}
catch (Exception ex)
{
result.Exception = new AssertCallbackException(ex);
break;
}

//onsuccess
try
{
Expand Down Expand Up @@ -351,6 +403,17 @@ private bool IsRetryException(Exception exception)
return true;
}

private async Task<bool> AssertThenRetry(RetryResult<T> result)
{
var stop = _condition?.Invoke(result) ?? true;
if (_conditionTask is not null)
{
stop = await _conditionTask(result);
}

return !stop;
}

private bool ShouldContinue(RetryResult<T> result, TimeSpan triedTime, int triedCount)
{
if (triedTime >= _retryOptions.MaxTryTime)
Expand Down
13 changes: 13 additions & 0 deletions src/RetryCore/Exceptions/AssertCallbackException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace Retry.Exceptions
{
public class AssertCallbackException : CallbackException
{
/// <inheritdoc />
public AssertCallbackException(Exception inner) : base(
"An exception occurs during Assert execution, see InnerException", inner)
{
}
}
}
38 changes: 36 additions & 2 deletions src/RetryCore/IAsyncRetriable.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -121,6 +121,24 @@ public Task<RetryResult> RunAsync(CancellationToken cancellationToken = default,
/// <param name="failureAction">The action to take on failure.</param>
/// <returns></returns>
public IAsyncRetriable OnFailureAsync(Func<RetryResult, int, Task> failureAction);

/// <summary>
/// Retries the task until the specified condition return true,
/// or the max try time/count is exceeded, or an exception is thrown druing task execution.
/// Then returns the value returned by the task.
/// </summary>
/// <param name = "condition">The assert condition.</param>
/// <returns></returns>
public IAsyncRetriable Assert(Func<RetryResult, bool> condition);

/// <summary>
/// Retries the task until the specified condition return true,
/// or the max try time/count is exceeded, or an exception is thrown druing task execution.
/// Then returns the value returned by the task.
/// </summary>
/// <param name = "condition">The assert condition.</param>
/// <returns></returns>
public IAsyncRetriable Assert(Func<RetryResult, Task<bool>> condition);
}

public interface IAsyncRetriable<T>
Expand Down Expand Up @@ -247,5 +265,21 @@ public Task<RetryResult<T>> RunAsync(CancellationToken cancellationToken = defau
/// <returns></returns>
public IAsyncRetriable<T> OnFailureAsync(Func<RetryResult<T>, int, Task> failureAction);

//public void RetryWhenResult();
/// <summary>
/// Retries the task until the specified condition return true,
/// or the max try time/count is exceeded, or an exception is thrown druing task execution.
/// Then returns the value returned by the task.
/// </summary>
/// <param name = "condition">The assert condition.</param>
/// <returns></returns>
public IAsyncRetriable<T> Assert(Func<RetryResult<T>, bool> condition);

/// <summary>
/// Retries the task until the specified condition return true,
/// or the max try time/count is exceeded, or an exception is thrown druing task execution.
/// Then returns the value returned by the task.
/// </summary>
/// <param name = "condition">The assert condition.</param>
/// <returns></returns>
public IAsyncRetriable<T> Assert(Func<RetryResult<T>, Task<bool>> condition);
}
20 changes: 19 additions & 1 deletion src/RetryCore/IRetriable.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;

namespace Retry;

Expand Down Expand Up @@ -67,6 +67,15 @@ public interface IRetriable
/// <param name="failureAction">The action to take on failure.</param>
/// <returns></returns>
public IRetriable OnFailure(Action<RetryResult, int> failureAction);

/// <summary>
/// Retries the task until the specified condition return true,
/// or the max try time/count is exceeded, or an exception is thrown druing task execution.
/// Then returns the value returned by the task.
/// </summary>
/// <param name = "condition">The assert condition.</param>
/// <returns></returns>
public IRetriable Assert(Func<RetryResult, bool> condition);
}

public interface IRetriable<T>
Expand Down Expand Up @@ -134,4 +143,13 @@ public interface IRetriable<T>
/// <param name="failureAction">The action to take on failure.</param>
/// <returns></returns>
public IRetriable<T> OnFailure(Action<RetryResult<T>, int> failureAction);

/// <summary>
/// Retries the task until the specified condition return true,
/// or the max try time/count is exceeded, or an exception is thrown druing task execution.
/// Then returns the value returned by the task.
/// </summary>
/// <param name = "condition">The assert condition.</param>
/// <returns></returns>
public IRetriable<T> Assert(Func<RetryResult<T>, bool> condition);
}
22 changes: 11 additions & 11 deletions src/RetryCore/RetryBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand Down Expand Up @@ -33,40 +33,40 @@ public RetryBuilder()
/// Builds this instance.
/// </summary>
/// <returns></returns>
public IRetriable Build(Action tryTask)
public IRetriable Build(Action @try)
{
return new RetryTask(tryTask, GetOptions(), GetRetryExceptions());
return new RetryTask(@try, GetOptions(), GetRetryExceptions());
}

/// <summary>
/// Builds the specified try task.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tryTask">The try task.</param>
/// <param name="try">The try task.</param>
/// <returns></returns>
public IRetriable<T> Build<T>(Func<T> tryTask)
public IRetriable<T> Build<T>(Func<T> @try)
{
return new RetryTask<T>(tryTask, GetOptions(), GetRetryExceptions());
return new RetryTask<T>(@try, GetOptions(), GetRetryExceptions());
}

/// <summary>
/// Builds this instance.
/// </summary>
/// <returns></returns>
public IAsyncRetriable Build(Func<Task> tryTask)
public IAsyncRetriable Build(Func<Task> @try)
{
return new AsyncRetryTask(tryTask, GetOptions(), GetRetryExceptions());
return new AsyncRetryTask(@try, GetOptions(), GetRetryExceptions());
}

/// <summary>
/// Builds the specified try task.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tryTask">The try task.</param>
/// <param name="try">The try task.</param>
/// <returns></returns>
public IAsyncRetriable<T> Build<T>(Func<Task<T>> tryTask)
public IAsyncRetriable<T> Build<T>(Func<Task<T>> @try)
{
return new AsyncRetryTask<T>(tryTask, GetOptions(), GetRetryExceptions());
return new AsyncRetryTask<T>(@try, GetOptions(), GetRetryExceptions());
}

private Type[] GetRetryExceptions()
Expand Down
2 changes: 1 addition & 1 deletion src/RetryCore/RetryCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<LangVersion>latest</LangVersion>

<Version>0.1.0</Version>
<Version>0.2.0</Version>
<PackageId>$(AssemblyName)</PackageId>
<Description>A library for retrying operations.</Description>
<Authors>jerviscui</Authors>
Expand Down
39 changes: 39 additions & 0 deletions src/RetryCore/RetryTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ IRetriable IRetriable.OnFailure(Action<RetryResult, int> failureAction)

return this;
}

/// <inheritdoc />
public IRetriable Assert(Func<RetryResult, bool> condition)
{
_retryTask = _retryTask.Assert(condition);

return this;
}
}

/// <summary>
Expand Down Expand Up @@ -124,6 +132,8 @@ public RetryTask(Func<T> function, RetryOptions retryOptions, Type[] retryExcept

private readonly List<Action<RetryResult<T>, int>> _failureActions;

private Func<RetryResult<T>, bool>? _condition;

/// <inheritdoc />
public IAsyncRetriable<T> AsAsync()
{
Expand Down Expand Up @@ -178,6 +188,14 @@ public IRetriable<T> OnFailure(Action<RetryResult<T>, int> failureAction)
return this;
}

/// <inheritdoc />
public IRetriable<T> Assert(Func<RetryResult<T>, bool> condition)
{
_condition = condition;

return this;
}

private RetryResult<T> TryImpl()
{
//TraceSource.TraceVerbose("Starting trying with max try time {0} and max try count {1}.",
Expand Down Expand Up @@ -232,6 +250,20 @@ private RetryResult<T> TryImpl()
break;
}

//assert
try
{
if (AssertThenRetry(result))
{
continue;
}
}
catch (Exception ex)
{
result.Exception = new AssertCallbackException(ex);
break;
}

//onsuccess
try
{
Expand Down Expand Up @@ -276,6 +308,13 @@ private bool IsRetryException(Exception exception)
return true;
}

private bool AssertThenRetry(RetryResult<T> result)
{
var stop = _condition?.Invoke(result) ?? true;

return !stop;
}

private bool ShouldContinue(RetryResult<T> result, TimeSpan triedTime, int triedCount)
{
if (triedTime >= _retryOptions.MaxTryTime)
Expand Down
Loading

0 comments on commit 932540d

Please sign in to comment.