Skip to content

Commit

Permalink
Fixes #1 : Allow arbitrary data to be passed to policy execution
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-wolfenden committed Jun 16, 2013
1 parent 19ddd18 commit c28ce96
Show file tree
Hide file tree
Showing 19 changed files with 1,155 additions and 60 deletions.
17 changes: 17 additions & 0 deletions src/Polly.Net35/Context.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using Polly.Utilities;

namespace Polly
{
/// <summary>
/// A readonly dictionary of string key / object value pairs
/// </summary>
public class Context : ReadOnlyDictionary<string, object>
{
internal static Context Empty = new Context(new Dictionary<string, object>());

internal Context(IDictionary<string, object> values) : base(values)
{
}
}
}
92 changes: 92 additions & 0 deletions src/Polly.Net35/ContextualPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Polly
{
/// <summary>
/// Transient exception handling policies that can be applied to delegates.
/// These policies can be called with arbitrary context data.
/// </summary>
public class ContextualPolicy
{
private readonly Action<Action, Context> _exceptionPolicy;

internal ContextualPolicy(Action<Action, Context> exceptionPolicy)
{
if (exceptionPolicy == null) throw new ArgumentNullException("exceptionPolicy");

_exceptionPolicy = exceptionPolicy;
}

/// <summary>
/// Executes the specified action within the policy.
/// </summary>
/// <param name="action">The action to perform.</param>
/// <param name="contextData">Arbitrary data that is passed to the exception policy.</param>
/// <exception cref="System.ArgumentNullException">contextData</exception>
[DebuggerStepThrough]
public void Execute(Action action, IDictionary<string, object> contextData)
{
if (contextData == null) throw new ArgumentNullException("contextData");

Execute(action, new Context(contextData));
}

/// <summary>
/// Executes the specified action within the policy.
/// </summary>
/// <param name="action">The action to perform.</param>
[DebuggerStepThrough]
public void Execute(Action action)
{
Execute(action, Context.Empty);
}

[DebuggerStepThrough]
private void Execute(Action action, Context context)
{
_exceptionPolicy(action, context);
}

/// <summary>
/// Executes the specified action within the policy and returns the result.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="action">The action to perform.</param>
/// <param name="contextData">Arbitrary data that is passed to the exception policy.</param>
/// <returns>
/// The value returned by the action
/// </returns>
/// <exception cref="System.ArgumentNullException">contextData</exception>
[DebuggerStepThrough]
public TResult Execute<TResult>(Func<TResult> action, IDictionary<string, object> contextData)
{
if (contextData == null) throw new ArgumentNullException("contextData");

return Execute(action, new Context(contextData));
}

/// <summary>
/// Executes the specified action within the policy and returns the result.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="action">The action to perform.</param>
/// <returns>
/// The value returned by the action
/// </returns>
[DebuggerStepThrough]
public TResult Execute<TResult>(Func<TResult> action)
{
return Execute(action, Context.Empty);
}

[DebuggerStepThrough]
private TResult Execute<TResult>(Func<TResult> action, Context context)
{
var result = default(TResult);
_exceptionPolicy(() => { result = action(); }, context);
return result;
}
}
}
3 changes: 3 additions & 0 deletions src/Polly.Net35/Polly.Net35.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
<Compile Include="CircuitBreaker\CircuitBreakerState.cs" />
<Compile Include="CircuitBreaker\ICircuitBreakerState.cs" />
<Compile Include="CircuitBreaker\BrokenCircuitException.cs" />
<Compile Include="Context.cs" />
<Compile Include="ContextualPolicy.cs" />
<Compile Include="ExceptionPredicate.cs" />
<Compile Include="OrSyntax.cs" />
<Compile Include="Policy.cs" />
Expand All @@ -70,6 +72,7 @@
<Compile Include="Retry\RetryPolicyState.cs" />
<Compile Include="Retry\RetryPolicyStateWithCount.cs" />
<Compile Include="Retry\RetryPolicyStateWithSleep.cs" />
<Compile Include="Utilities\ReadOnlyDictionary.cs" />
<Compile Include="Utilities\SystemClock.cs" />
<Compile Include="Utilities\TimedLock.cs" />
</ItemGroup>
Expand Down
13 changes: 10 additions & 3 deletions src/Polly.Net35/Retry/RetryPolicyState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,23 @@ namespace Polly.Retry
{
internal class RetryPolicyState : IRetryPolicyState
{
private readonly Action<Exception> _onRetry;
private readonly Action<Exception, Context> _onRetry;
private readonly Context _context;

public RetryPolicyState(Action<Exception> onRetry)
public RetryPolicyState(Action<Exception, Context> onRetry, Context context)
{
_onRetry = onRetry;
_context = context;
}

public RetryPolicyState(Action<Exception> onRetry) :
this((exception, context) => onRetry(exception), null)
{
}

public bool CanRetry(Exception ex)
{
_onRetry(ex);
_onRetry(ex, _context);
return true;
}
}
Expand Down
13 changes: 10 additions & 3 deletions src/Polly.Net35/Retry/RetryPolicyStateWithCount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ internal class RetryPolicyStateWithCount : IRetryPolicyState
{
private int _errorCount;
private readonly int _retryCount;
private readonly Action<Exception, int> _onRetry;
private readonly Action<Exception, int, Context> _onRetry;
private readonly Context _context;

public RetryPolicyStateWithCount(int retryCount, Action<Exception, int> onRetry)
public RetryPolicyStateWithCount(int retryCount, Action<Exception, int, Context> onRetry, Context context)
{
_retryCount = retryCount;
_onRetry = onRetry;
_context = context;
}

public RetryPolicyStateWithCount(int retryCount, Action<Exception, int> onRetry) :
this(retryCount, (exception, i, context) => onRetry(exception, i), null)
{
}

public bool CanRetry(Exception ex)
Expand All @@ -21,7 +28,7 @@ public bool CanRetry(Exception ex)
var shouldRetry = _errorCount <= _retryCount;
if (shouldRetry)
{
_onRetry(ex, _errorCount);
_onRetry(ex, _errorCount, _context);
}

return shouldRetry;
Expand Down
15 changes: 11 additions & 4 deletions src/Polly.Net35/Retry/RetryPolicyStateWithSleep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,28 @@ namespace Polly.Retry
{
internal class RetryPolicyStateWithSleep : IRetryPolicyState
{
private readonly Action<Exception, TimeSpan> _onRetry;
private readonly Action<Exception, TimeSpan, Context> _onRetry;
private readonly Context _context;
private readonly IEnumerator<TimeSpan> _sleepDurationsEnumerator;

public RetryPolicyStateWithSleep(IEnumerable<TimeSpan> sleepDurations, Action<Exception, TimeSpan> onRetry)
public RetryPolicyStateWithSleep(IEnumerable<TimeSpan> sleepDurations, Action<Exception, TimeSpan, Context> onRetry, Context context)
{
_sleepDurationsEnumerator = sleepDurations.GetEnumerator();
_onRetry = onRetry;
_context = context;
_sleepDurationsEnumerator = sleepDurations.GetEnumerator();
}

public RetryPolicyStateWithSleep(IEnumerable<TimeSpan> sleepDurations, Action<Exception, TimeSpan> onRetry) :
this(sleepDurations, (exception, span, context) => onRetry(exception, span), null)
{
}

public bool CanRetry(Exception ex)
{
if (!_sleepDurationsEnumerator.MoveNext()) return false;

var currentTimeSpan = _sleepDurationsEnumerator.Current;
_onRetry(ex, currentTimeSpan);
_onRetry(ex, currentTimeSpan, _context);

SystemClock.Sleep(currentTimeSpan);

Expand Down
Loading

0 comments on commit c28ce96

Please sign in to comment.