/// <summary> /// Routes the call using the ResolverFrx /// </summary> /// <param name="sAddress">Address which the call was sent to</param> /// <param name="Context">Dictionary of context variables used for routing and/or processing</param> /// <param name="Body">Message Body/Call Body</param> /// <param name="overrideDefaultExecutionStrategy">overrides the router's default execution strategy</param> /// <returns>Routing Result</returns> public virtual async Task <RER> RouteAsync(string sAddress, IDictionary <string, object> Context, Stream Body, ContextExecuteStrategyBase overrideDefaultExecutionStrategy) { // context management var chs = overrideDefaultExecutionStrategy == null ? mDefaultContextExecuteStrategy : overrideDefaultExecutionStrategy; RoutingContextBase re; RER rer; Context = null != Context ? Context : new Dictionary <string, object>(); // can be used by various sub system involved to reach the router, unique call instance id, or the trace log Context.Add(Context_Router_Call_InstanceId_Key, Guid.NewGuid().ToString()); // instance id #region Resolve try { re = await ResolveAsync(sAddress, Context, Body); } // caller can handle this ae, or RouterResolveException catch (AggregateException ae) { throw new RouterResolveException(ae); } catch (Exception e) { // this is either a telemetry error, and shouldn't happen in runtime // (unless you are doing something funny with the telemetry sub system) // or you have a sub class that is doing something funny. throw new RouterResolveException(e); } #endregion // if no resolver is matching then we need return null if (null == re) { return(null); } #region Execute try { rer = await ExecuteContextAsync(re, chs); } catch { throw; } finally { // context maintenance // just in case the caller intersted in reusing the dictionary Context.Remove(Context_Router_Call_InstanceId_Key); } return(rer); #endregion }
public static ContextExecuteStrategyBase ThenTryAgain(this ContextExecuteStrategyBase strategy, int times, int DelayMs) { var current = strategy; for (var i = 1; i <= times; i++) { current.Next = new RetryAfterStrategy(DelayMs); current = current.Next; } return(current); }
/// <summary> /// chains multiple retries with different backoffs /// </summary> /// <param name="strategy"></param> /// <param name="times"></param> /// <param name="DelayMs"></param> /// <param name="delayFactor"></param> /// <returns></returns> public static ContextExecuteStrategyBase ThenTryAgainWithBackOff(this ContextExecuteStrategyBase strategy, int times, int DelayMs, float delayFactor) { var current = strategy; for (var i = 1; i <= times; i++) { var actualDelay = 1 == i ? DelayMs : i * delayFactor * DelayMs; current.Next = new RetryAfterStrategy((int)actualDelay); current = current.Next; } return(current); }
protected virtual async Task <RER> ExecuteContextAsync(RoutingContextBase re, ContextExecuteStrategyBase chs) { RER rer = null; Stopwatch sw = new Stopwatch(); var currentChs = chs; ContextExecuteModeBase ExecuteMode = new DoNotRetryMode(); var TryCount = 1; var bSucess = false; while (true) { try { sw.Start(); rer = (RER)await re.ExecuteAsync(ExecuteMode); sw.Stop(); bSucess = true; } catch (Exception e) { if (null == currentChs) { throw; } TryCount++; // circut breaker if (TryCount > mMaxRetryCount) { throw new RouterMaxedRetryException(new AggregateException(e)) { RetryCount = (TryCount - 1), RoutingContext = re } } ; try { // execute current strategy; ExecuteMode = await currentChs.ExecuteStrategyAsync(TryCount, re, new AggregateException(e)); } catch (Exception StrategyExecuteFail) { // if we failed to execute strategy we just wrap the exception // along with the orginal execution one. throw new FailedToExecuteStrategyException(StrategyExecuteFail, e) { TryCount = TryCount, RoutingContext = re }; } // move to next strategy currentChs = currentChs.Next; if (!ExecuteMode.ShouldRouterTryAgain) { throw new AggregateException(e); } } finally { OnTelemetryExecute(re, rer, sw.Elapsed.TotalMilliseconds); Trace.WriteLine(string.Format("Execute in {0} Call Count {1} Routing Type:{2}", sw.Elapsed.TotalMilliseconds, TryCount, re.RouteExecuteType), "Verbose"); sw.Reset(); // reset the clock } if (bSucess) { break; // exit the loop } } return(rer); }
public static ContextExecuteStrategyBase ThrowIfExceptionIsIn(this ContextExecuteStrategyBase strategy, params Exception[] exceptions) { return(strategy.Then(new ThrowIfInnerExceptionNotIn(exceptions))); }
public virtual ContextExecuteStrategyBase Then(ContextExecuteStrategyBase next) { this.Next = next; return(this.Next); }