Skip to content

Commit

Permalink
Merge pull request #244 from reisenberger/reisenberger/feature/expand…
Browse files Browse the repository at this point in the history
…contextusage

v5.1.0: Allow different parts of an execution to exchange state through `Context` flowing with execution
  • Loading branch information
joelhulen authored May 4, 2017
2 parents 4a35b2e + 81f8806 commit e41321d
Show file tree
Hide file tree
Showing 91 changed files with 4,780 additions and 2,754 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 5.1.0
- Allow different parts of a policy execution to exchange data via a mutable Context travelling with each execution.

## 5.0.6
- Update NETStandard.Library dependency to latest 1.6.1 for .NetStandard1.0 target. Resolves compatibility for some Xamarin targets.

Expand Down Expand Up @@ -33,12 +36,14 @@
## 5.0.0 alpha

A major release, adding significant new resilience policies:

- Timeout policy: allows timing out any execution. Thanks to [@reisenberger](https://github.com/reisenberger).
- Bulkhead isolation policy: limits the resources consumable by governed actions, such that a faulting channel cannot cause cascading failures. Thanks to [@reisenberger](https://github.com/reisenberger) and contributions from [@brunolauze](https://github.com/brunolauze).
- Fallback policy: provides for a fallback execution or value, in case of overall failure. Thanks to [@reisenberger](https://github.com/reisenberger)
- PolicyWrap: allows flexibly combining Policy instances of any type, to form an overall resilience strategy. Thanks to [@reisenberger](https://github.com/reisenberger)

Other changes include:

- Add PolicyKeys and context to all policy executions, for logging and to support later introduction of policy events and metrics. Thanks to [@reisenberger](https://github.com/reisenberger)
- Add CancellationToken support to synchronous executions. Thanks to [@brunolauze](https://github.com/brunolauze) and [@reisenberger](https://github.com/reisenberger)
- Add some missing ExecuteAndCapture/Async overloads. Thanks to [@reisenberger](https://github.com/reisenberger)
Expand Down
2 changes: 1 addition & 1 deletion GitVersionConfig.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
next-version: 5.0.6
next-version: 5.1.0
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ From Polly v4.3.0 onwards, policies wrapping calls returning a `TResult` can als
```csharp
// Handle return value with condition
Policy
.HandleResult<HttpResponse>(r => r.StatusCode == 404)
.HandleResult<HttpResponseMessage>(r => r.StatusCode == 404)

// Handle multiple return values
Policy
.HandleResult<HttpResponse>(r => r.StatusCode == 500)
.OrResult<HttpResponse>(r => r.StatusCode == 502)
.HandleResult<HttpResponseMessage>(r => r.StatusCode == 500)
.OrResult<HttpResponseMessage>(r => r.StatusCode == 502)

// Handle primitive return values (implied use of .Equals())
Policy
Expand All @@ -93,9 +93,9 @@ Policy

// Handle both exceptions and return values in one policy
int[] httpStatusCodesWorthRetrying = {408, 500, 502, 503, 504};
HttpResponse result = Policy
.Handle<HttpException>()
.OrResult<HttpResponse>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
HttpResponseMessage result = Policy
.Handle<HttpResponseException>()
.OrResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
```

For more information, see [Handling Return Values](#handing-return-values-and-policytresult) at foot of this readme.
Expand Down Expand Up @@ -723,11 +723,11 @@ As described at step 1b, from Polly v4.3.0 onwards, policies can handle return v
```csharp
// Handle both exceptions and return values in one policy
int[] httpStatusCodesWorthRetrying = {408, 500, 502, 503, 504};
HttpResponse result = Policy
.Handle<HttpException>()
.OrResult<HttpResponse>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
HttpResponseMessage result = Policy
.Handle<HttpResponseException>()
.OrResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
.Retry(...)
.Execute( /* some Func<HttpResponse> */ )
.Execute( /* some Func<HttpResponseMessage> */ )
```

The exceptions and return results to handle can be expressed fluently in any order.
Expand Down Expand Up @@ -825,6 +825,7 @@ For details of changes by release see the [change log](https://github.com/App-vN
* [@lakario](https://github.com/lakario) - Tidy CircuitBreaker LastException property.
* [@lakario](https://github.com/lakario) - Add NoOpPolicy.
* [@Julien-Mialon](https://github.com/Julien-Mialon) - Fixes, support and examples for .NETStandard compatibility with Xamarin PCL projects
* [@reisenberger](https://github.com/reisenberger) - Add mutable Context and extra overloads taking Context. Allows different parts of a policy execution to exchange data via the mutable Context travelling with each execution.
# Sample Projects
Expand Down
4 changes: 4 additions & 0 deletions src/Polly.Net40Async.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
<releaseNotes>
v5.0 is a major release with significant new resilience policies: Timeout; Bulkhead Isolation; Fallback; and PolicyWrap. See release notes back to v5.0.0 for full details.

5.1.0
---------------------
- Allow different parts of a policy execution to exchange data via a mutable Context travelling with each execution.

5.0.6
---------------------
- (.NETStandard1.0 changes only.)
Expand Down
2 changes: 1 addition & 1 deletion src/Polly.NetStandard10/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Runtime.CompilerServices;

[assembly: AssemblyTitle("Polly")]
[assembly: AssemblyVersion("5.0.6.0")]
[assembly: AssemblyVersion("5.1.0.0")]
[assembly: CLSCompliant(true)]

[assembly: InternalsVisibleTo("Polly.Pcl.Specs")]
4 changes: 2 additions & 2 deletions src/Polly.Shared/Bulkhead/BulkheadEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Polly.Bulkhead
internal static partial class BulkheadEngine
{
internal static TResult Implementation<TResult>(
Func<CancellationToken, TResult> action,
Func<Context, CancellationToken, TResult> action,
Context context,
Action<Context> onBulkheadRejected,
SemaphoreSlim maxParallelizationSemaphore,
Expand All @@ -31,7 +31,7 @@ internal static TResult Implementation<TResult>(
maxParallelizationSemaphore.Wait(cancellationToken);
try
{
return action(cancellationToken);
return action(context, cancellationToken);
}
finally
{
Expand Down
4 changes: 2 additions & 2 deletions src/Polly.Shared/Bulkhead/BulkheadEngineAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Polly.Bulkhead
internal static partial class BulkheadEngine
{
internal static async Task<TResult> ImplementationAsync<TResult>(
Func<CancellationToken, Task<TResult>> action,
Func<Context, CancellationToken, Task<TResult>> action,
Context context,
Func<Context, Task> onBulkheadRejectedAsync,
SemaphoreSlim maxParallelizationSemaphore,
Expand All @@ -33,7 +33,7 @@ internal static async Task<TResult> ImplementationAsync<TResult>(

try
{
return await action(cancellationToken).ConfigureAwait(continueOnCapturedContext);
return await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext);
}
finally
{
Expand Down
4 changes: 2 additions & 2 deletions src/Polly.Shared/Bulkhead/BulkheadPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public partial class BulkheadPolicy : Policy, IDisposable
private readonly int _maxQueueingActions;

internal BulkheadPolicy(
Action<Action<CancellationToken>, Context, CancellationToken> exceptionPolicy,
Action<Action<Context, CancellationToken>, Context, CancellationToken> exceptionPolicy,
int maxParallelization,
int maxQueueingActions,
SemaphoreSlim maxParallelizationSemaphore,
Expand Down Expand Up @@ -66,7 +66,7 @@ public partial class BulkheadPolicy<TResult> : Policy<TResult>, IDisposable
private readonly int _maxQueueingActions;

internal BulkheadPolicy(
Func<Func<CancellationToken, TResult>, Context, CancellationToken, TResult> executionPolicy,
Func<Func<Context, CancellationToken, TResult>, Context, CancellationToken, TResult> executionPolicy,
int maxParallelization,
int maxQueueingActions,
SemaphoreSlim maxParallelizationSemaphore,
Expand Down
4 changes: 2 additions & 2 deletions src/Polly.Shared/Bulkhead/BulkheadPolicyAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Polly.Bulkhead
{
public partial class BulkheadPolicy
{
internal BulkheadPolicy(Func<Func<CancellationToken, Task>, Context, CancellationToken, bool, Task> asyncExceptionPolicy,
internal BulkheadPolicy(Func<Func<Context, CancellationToken, Task>, Context, CancellationToken, bool, Task> asyncExceptionPolicy,
int maxParallelization,
int maxQueueingActions,
SemaphoreSlim maxParallelizationSemaphore,
Expand All @@ -30,7 +30,7 @@ internal BulkheadPolicy(Func<Func<CancellationToken, Task>, Context, Cancellatio
public partial class BulkheadPolicy<TResult>
{
internal BulkheadPolicy(
Func<Func<CancellationToken, Task<TResult>>, Context, CancellationToken, bool, Task<TResult>> asyncExecutionPolicy,
Func<Func<Context, CancellationToken, Task<TResult>>, Context, CancellationToken, bool, Task<TResult>> asyncExecutionPolicy,
int maxParallelization,
int maxQueueingActions,
SemaphoreSlim maxParallelizationSemaphore,
Expand Down
2 changes: 1 addition & 1 deletion src/Polly.Shared/Bulkhead/BulkheadSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static BulkheadPolicy Bulkhead(int maxParallelization, int maxQueuingActi

return new BulkheadPolicy(
(action, context, cancellationToken) => BulkheadEngine.Implementation(
ct => { action(ct); return EmptyStruct.Instance; },
(ctx, ct) => { action(ctx, ct); return EmptyStruct.Instance; },
context,
onBulkheadRejected,
maxParallelizationSemaphore,
Expand Down
2 changes: 1 addition & 1 deletion src/Polly.Shared/Bulkhead/BulkheadSyntaxAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public static BulkheadPolicy BulkheadAsync(int maxParallelization, int maxQueuin

return new BulkheadPolicy((action, context, cancellationToken, continueOnCapturedContext) =>
BulkheadEngine.ImplementationAsync(
async ct => { await action(ct).ConfigureAwait(continueOnCapturedContext); return EmptyStruct.Instance; },
async (ctx, ct) => { await action(ctx, ct).ConfigureAwait(continueOnCapturedContext); return EmptyStruct.Instance; },
context,
onBulkheadRejectedAsync,
maxParallelizationSemaphore,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public static CircuitBreakerPolicy AdvancedCircuitBreaker(this PolicyBuilder pol
onHalfOpen);
return new CircuitBreakerPolicy(
(action, context, cancellationToken) => CircuitBreakerEngine.Implementation<EmptyStruct>(
(ct) => { action(ct); return EmptyStruct.Instance; },
(ctx, ct) => { action(ctx, ct); return EmptyStruct.Instance; },
context,
cancellationToken,
policyBuilder.ExceptionPredicates,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public static CircuitBreakerPolicy AdvancedCircuitBreakerAsync(this PolicyBuilde
onHalfOpen);
return new CircuitBreakerPolicy(
(action, context, cancellationToken, continueOnCapturedContext) => CircuitBreakerEngine.ImplementationAsync<EmptyStruct>(
async ct => { await action(ct).ConfigureAwait(continueOnCapturedContext); return EmptyStruct.Instance; },
async (ctx, ct) => { await action(ctx, ct).ConfigureAwait(continueOnCapturedContext); return EmptyStruct.Instance; },
context,
policyBuilder.ExceptionPredicates,
PredicateHelper<EmptyStruct>.EmptyResultPredicates,
Expand Down
4 changes: 2 additions & 2 deletions src/Polly.Shared/CircuitBreaker/CircuitBreakerEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Polly.CircuitBreaker
internal partial class CircuitBreakerEngine
{
internal static TResult Implementation<TResult>(
Func<CancellationToken, TResult> action,
Func<Context, CancellationToken, TResult> action,
Context context,
CancellationToken cancellationToken,
IEnumerable<ExceptionPredicate> shouldHandleExceptionPredicates,
Expand All @@ -21,7 +21,7 @@ internal static TResult Implementation<TResult>(

try
{
TResult result = action(cancellationToken);
TResult result = action(context, cancellationToken);

if (shouldHandleResultPredicates.Any(predicate => predicate(result)))
{
Expand Down
4 changes: 2 additions & 2 deletions src/Polly.Shared/CircuitBreaker/CircuitBreakerEngineAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Polly.CircuitBreaker
internal partial class CircuitBreakerEngine
{
internal static async Task<TResult> ImplementationAsync<TResult>(
Func<CancellationToken, Task<TResult>> action,
Func<Context, CancellationToken, Task<TResult>> action,
Context context,
IEnumerable<ExceptionPredicate> shouldHandleExceptionPredicates,
IEnumerable<ResultPredicate<TResult>> shouldHandleResultPredicates,
Expand All @@ -25,7 +25,7 @@ internal static async Task<TResult> ImplementationAsync<TResult>(

try
{
TResult result = await action(cancellationToken).ConfigureAwait(continueOnCapturedContext);
TResult result = await action(context, cancellationToken).ConfigureAwait(continueOnCapturedContext);

if (shouldHandleResultPredicates.Any(predicate => predicate(result)))
{
Expand Down
4 changes: 2 additions & 2 deletions src/Polly.Shared/CircuitBreaker/CircuitBreakerPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public partial class CircuitBreakerPolicy : Policy
internal readonly ICircuitController<EmptyStruct> _breakerController;

internal CircuitBreakerPolicy(
Action<Action<CancellationToken>, Context, CancellationToken> exceptionPolicy,
Action<Action<Context, CancellationToken>, Context, CancellationToken> exceptionPolicy,
IEnumerable<ExceptionPredicate> exceptionPredicates,
ICircuitController<EmptyStruct> breakerController
) : base(exceptionPolicy, exceptionPredicates)
Expand Down Expand Up @@ -63,7 +63,7 @@ public partial class CircuitBreakerPolicy<TResult> : Policy<TResult>
internal readonly ICircuitController<TResult> _breakerController;

internal CircuitBreakerPolicy(
Func<Func<CancellationToken, TResult>, Context, CancellationToken, TResult> executionPolicy,
Func<Func<Context, CancellationToken, TResult>, Context, CancellationToken, TResult> executionPolicy,
IEnumerable<ExceptionPredicate> exceptionPredicates,
IEnumerable<ResultPredicate<TResult>> resultPredicates,
ICircuitController<TResult> breakerController
Expand Down
4 changes: 2 additions & 2 deletions src/Polly.Shared/CircuitBreaker/CircuitBreakerPolicyAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Polly.CircuitBreaker
public partial class CircuitBreakerPolicy
{
internal CircuitBreakerPolicy(
Func<Func<CancellationToken, Task>, Context, CancellationToken, bool, Task> asyncExceptionPolicy,
Func<Func<Context, CancellationToken, Task>, Context, CancellationToken, bool, Task> asyncExceptionPolicy,
IEnumerable<ExceptionPredicate> exceptionPredicates,
ICircuitController<EmptyStruct> breakerController
) : base(asyncExceptionPolicy, exceptionPredicates)
Expand All @@ -22,7 +22,7 @@ ICircuitController<EmptyStruct> breakerController
public partial class CircuitBreakerPolicy<TResult>
{
internal CircuitBreakerPolicy(
Func<Func<CancellationToken, Task<TResult>>, Context, CancellationToken, bool, Task<TResult>> asyncExecutionPolicy,
Func<Func<Context, CancellationToken, Task<TResult>>, Context, CancellationToken, bool, Task<TResult>> asyncExecutionPolicy,
IEnumerable<ExceptionPredicate> exceptionPredicates,
IEnumerable<ResultPredicate<TResult>> resultPredicates,
ICircuitController<TResult> breakerController
Expand Down
2 changes: 1 addition & 1 deletion src/Polly.Shared/CircuitBreaker/CircuitBreakerSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public static CircuitBreakerPolicy CircuitBreaker(this PolicyBuilder policyBuild
onHalfOpen);
return new CircuitBreakerPolicy(
(action, context, cancellationToken) => CircuitBreakerEngine.Implementation(
(ct) => { action(ct); return EmptyStruct.Instance; },
(ctx, ct) => { action(ctx, ct); return EmptyStruct.Instance; },
context,
cancellationToken,
policyBuilder.ExceptionPredicates,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public static CircuitBreakerPolicy CircuitBreakerAsync(this PolicyBuilder policy
return new CircuitBreakerPolicy(
(action, context, cancellationToken, continueOnCapturedContext) =>
CircuitBreakerEngine.ImplementationAsync(
async ct => { await action(ct).ConfigureAwait(continueOnCapturedContext); return EmptyStruct.Instance; },
async (ctx, ct) => { await action(ctx, ct).ConfigureAwait(continueOnCapturedContext); return EmptyStruct.Instance; },
context,
policyBuilder.ExceptionPredicates,
PredicateHelper<EmptyStruct>.EmptyResultPredicates,
Expand Down
35 changes: 11 additions & 24 deletions src/Polly.Shared/Context.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
using System;
using System.Collections.Generic;
using Polly.Wrap;
#if SUPPORTS_READONLY_COLLECTION
using System.Collections.ObjectModel;
#else
using Polly.Utilities;
#endif

namespace Polly
{
/// <summary>
/// A readonly dictionary of string key / object value pairs
/// Context that carries with a single execution through a Policy. Commonly-used properties are directly on the class. Backed by a dictionary of string key / object value pairs, to which user-defined values may be added.
/// <remarks>Do not re-use an instance of <see cref="Context"/> across more than one execution.</remarks>
/// </summary>
public class Context : ReadOnlyDictionary<string, object>
public class Context : Dictionary<string, object>
{
// For an individual execution through a policy or policywrap, it is expected that all execution steps (for example executing the user delegate, invoking policy-activity delegates such as onRetry, onBreak, onTimeout etc) execute sequentially.
// Therefore, this class is intentionally not constructed to be safe for concurrent access from multiple threads.

private static readonly IDictionary<string, object> emptyDictionary = new Dictionary<string, object>();
internal static readonly Context None = new Context(emptyDictionary);

private string _policyKey;
private string _policyWrapKey;
private readonly string _executionKey;
private Guid? _executionGuid;

/// <summary>
Expand All @@ -37,7 +32,7 @@ public Context(String executionKey) : this(executionKey, emptyDictionary)
/// <param name="contextData">The context data.</param>
public Context(String executionKey, IDictionary<string, object> contextData) : this(contextData)
{
_executionKey = executionKey;
ExecutionKey = executionKey;
}

internal Context() : this(emptyDictionary)
Expand All @@ -50,28 +45,20 @@ internal Context(IDictionary<string, object> contextData) : base(contextData)
}

/// <summary>
/// A key unique to the outermost <see cref="PolicyWrap"/> instance involved in the current PolicyWrap execution.
/// A key unique to the outermost <see cref="Polly.Wrap.PolicyWrap"/> instance involved in the current PolicyWrap execution.
/// </summary>
public String PolicyWrapKey
{
get { return _policyWrapKey; }
internal set { _policyWrapKey = value; }
}
public String PolicyWrapKey { get; internal set; }

/// <summary>
/// A key unique to the <see cref="Policy"/> instance executing the current delegate.
/// </summary>
public String PolicyKey
{
get { return _policyKey; }
internal set { _policyKey = value; }
}
public String PolicyKey { get; internal set; }

/// <summary>
/// A key unique to the call site of the current execution.
/// <remarks>The value is set </remarks>
/// </summary>
public String ExecutionKey => _executionKey;
public String ExecutionKey { get; }

/// <summary>
/// A Guid guaranteed to be unique to each execution.
Expand Down
Loading

0 comments on commit e41321d

Please sign in to comment.