Skip to content

Commit

Permalink
Merge development branch for v5.6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
reisenberger authored Nov 26, 2017
2 parents 24165be + 3f76b98 commit 9c133b6
Show file tree
Hide file tree
Showing 81 changed files with 2,334 additions and 232 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ TestResults
*.user
*.sln.docstates
.vs/
.vscode/

# Build results
[Dd]ebug/
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 5.6.0
- Add ability to handle inner exceptions natively: .HandleInner<TEx>()
- Allow WaitAndRetry policies to calculate wait based on the handled fault
- Add the ability to access the policies within an IPolicyWrap
- Allow PolicyWrap to configure policies expressed as interfaces
- Bug fix: set context keys for generic execute methods with PolicyWrap
- Bug fix: generic TResult method with non-generic fallback policy
- Performance improvements
- Multiple build speed improvements

## 5.5.0
- Bug fix: non-generic CachePolicy with PolicyWrap
- Add Cache interfaces
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.5.0
next-version: 5.6.0
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ You can install the Strongly Named version via:
Install-Package Polly.Net40Async-Signed



# Resilience policies

Polly offers multiple resilience policies:
Expand All @@ -52,8 +51,6 @@ Fault-handling policies handle specific exceptions thrown by, or results returne

### (for fault-handling policies: Retry family, CircuitBreaker family and Fallback)



```csharp
// Single exception type
Policy
Expand All @@ -72,6 +69,11 @@ Policy
Policy
.Handle<SqlException>(ex => ex.Number == 1205)
.Or<ArgumentException>(ex => ex.ParamName == "example")

// Inner exceptions of ordinary exceptions or AggregateException, with or without conditions
Policy
.HandleInner<HttpResponseException>()
.OrInner<OperationCanceledException>(ex => ex.CancellationToken == myToken)
```

## Step 1b: (optionally) Specify return results you want to handle
Expand Down Expand Up @@ -938,6 +940,13 @@ For details of changes by release see the [change log](https://github.com/App-vN
* [@jiimaho](https://github.com/jiimaho) and [@Extremo75](https://github.com/ExtRemo75) - Provide public factory methods for PolicyResult, to support testing.
* [@Extremo75](https://github.com/ExtRemo75) - Allow fallback delegates to take handled fault as input parameter.
* [@reisenberger](https://github.com/reisenberger) and [@seanfarrow](https://github.com/SeanFarrow) - Add CachePolicy, with interfaces for pluggable cache providers and serializers.
* Thanks to the awesome devs at [@tretton37](https://github.com/tretton37) who delivered the following as part of a one-day in-company hackathon led by [@reisenberger](https://github.com/reisenberger), sponsored by [@tretton37](https://github.com/tretton37) and convened by [@thecodejunkie](https://github.com/thecodejunkie)
* [@matst80](https://github.com/matst80) - Allow WaitAndRetry to take handled fault as an input to the sleepDurationProvider, allowing WaitAndRetry to take account of systems which specify a duration to wait as part of a fault response; eg Azure CosmosDB may specify this in `x-ms-retry-after-ms` headers or in a property to an exception thrown by the Azure CosmosDB SDK.
* [@MartinSStewart](https://github.com/martinsstewart) - Add GetPolicies() extension methods to IPolicyWrap.
* [@jbergens37](https://github.com/jbergens37) - Parallelize test running where possible, to improve overall build speed.
* [@reisenberger](https://github.com/reisenberger) - Add new .HandleInner<TException>(...) syntax for handling inner exceptions natively.
* [@rjongeneelen](https://github.com/rjongeneelen) and [@reisenberger](https://github.com/reisenberger) - Allow PolicyWrap configuration to configure policies via interfaces.
* [@reisenberger](https://github.com/reisenberger) - Performance improvements.
# Sample Projects

Expand Down
2 changes: 1 addition & 1 deletion src/Polly.Net40Async.Specs/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
using Xunit;

[assembly: AssemblyTitle("Polly.Net40Async.Specs")]
[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: CollectionBehavior(DisableTestParallelization = false)]
12 changes: 11 additions & 1 deletion src/Polly.Net40Async.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@
<tags>Exception Handling Resilience Transient Fault Policy Circuit Breaker CircuitBreaker Retry Wait Cache Cache-aside Bulkhead Fallback Timeout Throttle Parallelization</tags>
<copyright>Copyright © 2017, App vNext</copyright>
<releaseNotes>
v5.0 is a major release with significant new resilience policies: Timeout; Bulkhead Isolation; Fallback; Cache; and PolicyWrap. See release notes back to v5.0.0 for full details. v5.0.5 includes important circuit-breaker fixes.
v5.0 is a major release with significant new resilience policies: Timeout; Bulkhead Isolation; Fallback; Cache; and PolicyWrap. See release notes back to v5.0.0 for full details.

5.6.0
---------------------
- Add ability to handle inner exceptions natively: .HandleInner&lt;TEx&gt;()
- Allow WaitAndRetry policies to calculate wait based on the handled fault
- Add the ability to access the policies within an IPolicyWrap
- Allow PolicyWrap to take interfaces as parameters
- Bug fix: set context keys for generic execute method with PolicyWrap
- Bug fix: generic TResult method with non-generic fallback policy
- Performance improvements

5.5.0
---------------------
Expand Down
2 changes: 1 addition & 1 deletion src/Polly.Net45.Specs/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
using Xunit;

[assembly: AssemblyTitle("Polly.Net45.Specs")]
[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: CollectionBehavior(DisableTestParallelization = false)]
2 changes: 1 addition & 1 deletion src/Polly.NetStandard11.Specs/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[assembly: Xunit.CollectionBehavior(DisableTestParallelization = true)]
[assembly: Xunit.CollectionBehavior(DisableTestParallelization = false)]
2 changes: 1 addition & 1 deletion src/Polly.NetStandard11/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.5.0.0")]
[assembly: AssemblyVersion("5.6.0.0")]
[assembly: CLSCompliant(true)]

[assembly: InternalsVisibleTo("Polly.NetStandard11.Specs")]
16 changes: 14 additions & 2 deletions src/Polly.Shared/CircuitBreaker/CircuitBreakerEngine.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading;

#if NET40
using ExceptionDispatchInfo = Polly.Utilities.ExceptionDispatchInfo;
#endif

namespace Polly.CircuitBreaker
{
internal partial class CircuitBreakerEngine
Expand Down Expand Up @@ -36,13 +41,20 @@ internal static TResult Implementation<TResult>(
}
catch (Exception ex)
{
if (!shouldHandleExceptionPredicates.Any(predicate => predicate(ex)))
Exception handledException = shouldHandleExceptionPredicates
.Select(predicate => predicate(ex))
.FirstOrDefault(e => e != null);
if (handledException == null)
{
throw;
}

breakerController.OnActionFailure(new DelegateResult<TResult>(ex), context);
breakerController.OnActionFailure(new DelegateResult<TResult>(handledException), context);

if (handledException != ex)
{
ExceptionDispatchInfo.Capture(handledException).Throw();
}
throw;
}
}
Expand Down
20 changes: 15 additions & 5 deletions src/Polly.Shared/CircuitBreaker/CircuitBreakerEngineAsync.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@


using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;

#if NET40
using ExceptionDispatchInfo = Polly.Utilities.ExceptionDispatchInfo;
#endif

namespace Polly.CircuitBreaker
{
internal partial class CircuitBreakerEngine
Expand Down Expand Up @@ -40,13 +43,20 @@ internal static async Task<TResult> ImplementationAsync<TResult>(
}
catch (Exception ex)
{
if (!shouldHandleExceptionPredicates.Any(predicate => predicate(ex)))
Exception handledException = shouldHandleExceptionPredicates
.Select(predicate => predicate(ex))
.FirstOrDefault(e => e != null);
if (handledException == null)
{
throw;
}

breakerController.OnActionFailure(new DelegateResult<TResult>(ex), context);
breakerController.OnActionFailure(new DelegateResult<TResult>(handledException), context);

if (handledException != ex)
{
ExceptionDispatchInfo.Capture(handledException).Throw();
}
throw;
}

Expand Down
159 changes: 159 additions & 0 deletions src/Polly.Shared/Context.Dictionary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace Polly
{
/// <summary>
/// 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 partial class Context : IDictionary<string, object>, IDictionary
#if !NET40
, IReadOnlyDictionary<string, object>
#endif
{
// 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 Dictionary<string, object> wrappedDictionary = null;

private Dictionary<string, object> WrappedDictionary => wrappedDictionary ?? (wrappedDictionary = new Dictionary<string, object>());

/// <summary>
/// Initializes a new instance of the <see cref="Context"/> class, with the specified <paramref name="executionKey" /> and the supplied <paramref name="contextData"/>.
/// </summary>
/// <param name="executionKey">The execution key.</param>
/// <param name="contextData">The context data.</param>
public Context(String executionKey, IDictionary<string, object> contextData) : this(contextData)
{
ExecutionKey = executionKey;
}

internal Context(IDictionary<string, object> contextData) : this()
{
if (contextData == null) throw new ArgumentNullException(nameof(contextData));
wrappedDictionary = new Dictionary<string, object>(contextData);
}

#region IDictionary<string,object> implementation

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
public ICollection<string> Keys => WrappedDictionary.Keys;

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
public ICollection<object> Values => WrappedDictionary.Values;

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
public int Count => WrappedDictionary.Count;

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
bool ICollection<KeyValuePair<string, object>>.IsReadOnly => ((IDictionary<string, object>)WrappedDictionary).IsReadOnly;

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
public object this[string key]
{
get => WrappedDictionary[key];
set => WrappedDictionary[key] = value;
}

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
public void Add(string key, object value)
{
WrappedDictionary.Add(key, value);
}

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
public bool ContainsKey(string key) => WrappedDictionary.ContainsKey(key);

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
public bool Remove(string key) => WrappedDictionary.Remove(key);

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
public bool TryGetValue(string key, out object value) => WrappedDictionary.TryGetValue(key, out value);

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item) => ((IDictionary<string, object>)WrappedDictionary).Add(item);

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
public void Clear() => WrappedDictionary.Clear();

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item) => ((IDictionary<string, object>)WrappedDictionary).Contains(item);

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) => ((IDictionary<string, object>) WrappedDictionary).CopyTo(array, arrayIndex);

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item) => ((IDictionary<string, object>)WrappedDictionary).Remove(item);

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => WrappedDictionary.GetEnumerator();

/// <inheritdoc cref="IDictionary{TKey,Value}"/>
IEnumerator IEnumerable.GetEnumerator() => WrappedDictionary.GetEnumerator();

/// <inheritdoc cref="IDictionary"/>
public void Add(object key, object value)
{
((IDictionary)WrappedDictionary).Add(key, value);
}

/// <inheritdoc cref="IDictionary"/>
public bool Contains(object key)
{
return ((IDictionary)WrappedDictionary).Contains(key);
}

/// <inheritdoc cref="IDictionary"/>
IDictionaryEnumerator IDictionary.GetEnumerator()
{
return ((IDictionary)WrappedDictionary).GetEnumerator();
}

/// <inheritdoc cref="IDictionary"/>
public void Remove(object key)
{
((IDictionary)WrappedDictionary).Remove(key);
}

/// <inheritdoc cref="IDictionary"/>
public void CopyTo(Array array, int index)
{
((IDictionary)WrappedDictionary).CopyTo(array, index);
}

#endregion

#if !NET40
#region IReadOnlyDictionary<string, object> implementation
IEnumerable<string> IReadOnlyDictionary<string, object>.Keys => ((IReadOnlyDictionary<string, object>)WrappedDictionary).Keys;

IEnumerable<object> IReadOnlyDictionary<string, object>.Values => ((IReadOnlyDictionary<string, object>)WrappedDictionary).Values;
#endregion
#endif

#region IDictionary implementation

/// <inheritdoc cref="IDictionary"/>
bool IDictionary.IsFixedSize => ((IDictionary)WrappedDictionary).IsFixedSize;

/// <inheritdoc cref="IDictionary"/>
bool IDictionary.IsReadOnly => ((IDictionary)WrappedDictionary).IsReadOnly;

ICollection IDictionary.Keys => ((IDictionary)WrappedDictionary).Keys;

ICollection IDictionary.Values => ((IDictionary)WrappedDictionary).Values;

/// <inheritdoc cref="IDictionary"/>
bool ICollection.IsSynchronized => ((IDictionary)WrappedDictionary).IsSynchronized;

/// <inheritdoc cref="IDictionary"/>
object ICollection.SyncRoot => ((IDictionary)WrappedDictionary).SyncRoot;

/// <inheritdoc cref="IDictionary"/>
object IDictionary.this[object key] { get => ((IDictionary)WrappedDictionary)[key]; set => ((IDictionary)WrappedDictionary)[key] = value; }

#endregion
}
}
Loading

0 comments on commit 9c133b6

Please sign in to comment.