Polly: PROPOSAL: Tooling for InnerExceptions of AggregateException

Created on 8 Jun 2017  路  3Comments  路  Source: App-vNext/Polly

Background

Polly currently does not offer any extra tooling for handling InnerExceptions of AggregateException.

InnerExceptions of AggregateException can currently be handled, by writing eg

 .Handle<AggregateException>(ae => ae.Flatten().InnerExceptions.Any(ie => ie is ExceptionTypeIWantToHandle))

(and similar). But we have requests (1; 2; 3) for more in-built support.

Option (a) Make existing syntax automatically handle AggregateException.InnerExceptions

Make the existing .Handle<TException>(...) syntax _automatically_ extend to find InnerExceptions of AggregateException which match.

_Advantages_: Most concise; least work for the developer.

_Disadvantages_:

  • Breaking change to existing behaviour.
  • Not explicit. Polly has generally favoured syntax which makes operation clear and explicit, rather than 'hidden magic' (implicit effects), which developers have to keep in mind; which are not immediately obvious to a newcomer reading the code.
  • In being implicit, it would make _every_ execution check for inner exceptions (including executions for which this is entirely irrelevant), incurring a small performance penalty. Though the penalty would be small, as a library it should perhaps be avoided, with in mind those using Polly in very high throughput / low latency scenarios.

Option (b) Add new explicit syntax eg .HandleInner<>(...)

Add new explicit syntax .HandleInAggregate<TException>(...); or HandleInnerException<TException>(...).

_Advantages_:

  • No breaking change to existing behaviour.
  • Explicit - no 'hidden magic' which developers new to Polly have to be aware of.
  • No unnecessary performance penalty.

Assumptions for both options:

  • (i) Anywhere the discussion mentions .Handle...(), assume that equivalent .Or...() syntax is also meant; and that all variants of .Handle() (eg also the variant with an extra bool predicate) are meant.

  • (ii) Matching would find recursively nested inner exceptions, using eg AggregateException.Flatten() or similar.

  • (iii) Where any other aspect of a Polly policy expressed a handled exception (for example PolicyResult.FinalException with .ExecuteAndCapture(...); or when the handled exception is passed to policy delegates like onRetry or onBreak; or when a measured exception is rethrown by CircuitBreaker), Polly would always passed the matched, unwrapped inner exception rather than the wrapping exception. [Caveat: .NET4.0 does not support ExceptionDispatchInfo and might lose stack trace info or require workround]

Caveat to both options:

  • (iv) : Both (a) and (b) imply the _risk of losing information_ if an AggregateException wrapped both a matched exception and some other exception(s). Assumption (iii) above (promoting and returning the matched InnerException) would imply _discarding_ any other inner exceptions; these would _not_ be available to following code.

_Community views?_: does the advantage of (iii) outweigh the disadvantage of (iv)?

Observations:

  • AggregateException containing a single InnerException might be the more common scenario, from typical async/await usages; multiple InnerExceptions are more _usually_ connected with fork/join scenarios.

  • With either (a) or (b), it would still be possible to gain full access to the other InnerExceptions by handling the AggregateException directly using eg .Handle<AggregateException>(ae => ... ), in scenarios where (iv) was a concern. So there is a workround.


_Community views?_

Suggestions of different options / variations also welcome!

enhancement ready

All 3 comments

I believe that the .HandleInner<Exception>() syntax to a better option than implicit processing. As you mentioned, with it implicitly scanning inner exceptions it is a potentially breaking change for existing systems and I would be legitimately concerned about the performance impacts.

If implicit scanning were implemented, and the AggregateException wraps an AggregateException, what would be the expected behavior? By making the definition explicit, developers can extend their application's functionality as it suits them.

Ideally, the .HandleInner<Exception>() signature could have an overload which allows it to scan an exception's inner exception to a finite depth.

Another vote for .HandleInner<Exception>()

The following, IMHO, outweigh other considerations:

  • No breaking change to existing behaviour.
  • Explicit - no 'hidden magic' which developers new to Polly have to be aware of.

This feature is delivered in Polly v5.6.0 (will be released via nuget in next day or so).

Was this page helpful?
0 / 5 - 0 ratings