protected virtual string GetNextHostAddressInBalancingSet() { /* * Use the the address list as circular buffer with a pointer maintenaned * as a state. if the list is empty (or was emptied by mistake) return an exception. * * we cheated a bit here routing is * A-B-C * A-B-C * until we hit int.MaxValue then * C-B-A * C-B-A * until we hit 0 then * A-B-C * A-B-C * * Overall it is R/R */ var sStateKey = string.Format(State_Key_LoadBalancingSet, MatcherTreeId); var loadbalanceIdx = (LoadBalanceIdx)Resolver.State.StateEntries.GetOrAdd(sStateKey, (dictKey) => { return(new LoadBalanceIdx()); }); string nextAddress = null; while (true) { try { var newIdx = Math.Abs(Interlocked.Increment(ref loadbalanceIdx.Idx)); // if the list was emptied by mistake, we will go to DivideByZeroException nextAddress = TargetHostAddressList[newIdx % TargetHostAddressList.Count]; // so if address was removed after we picked it up, we just try agian if (TargetHostAddressList.Contains(nextAddress)) { break; } } catch (DivideByZeroException) { //somebody cleared the address list while we are trying to pick an address throw new InvalidOperationException("Load balancing set is empty"); } catch (ArgumentOutOfRangeException) { // this will happen if the list got replaced with a shorter list // after we picked a position > sizeof(new list). ingore and try again. } // anyother exception should be vented up the stack. } return(nextAddress); }
public override async Task <bool> MatchAsync(RoutingContextBase routingContext, string sAddress, IDictionary <string, object> Context, Stream Body) { // validate, null list is bad if (null == this.TargetHostAddressList) { throw new ArgumentNullException("TargetHostAddresses"); } // a list that has a null or empty is also bad var nullAddresses = TargetHostAddressList.Where(s => string.IsNullOrEmpty(s)); if (0 != nullAddresses.Count()) { throw new ArgumentNullException("TargetHostAddresses contains null or empty host addresses"); } if (false == await base.MatchAsync(routingContext, sAddress, Context, Body)) { return(false); } if (Clear) { routingContext.TargetHostAddressList.Clear(); } routingContext.TargetHostAddressList.AddRange(TargetHostAddressList); routingContext.RouteExecuteType = this.RoutingType; return(true); }
public override async Task <RoutingResultBase> ExecuteAsync(ContextExecuteModeBase executeMode) { // validate that the passed execution mode is supported by this context. if (!IsAllowedExecutionMode(executeMode)) { throw new NotSupportedExecuteModeException(string.Format("Context of type {0} can not support execute mode of type {1}", this.GetType().ToString(), executeMode.GetType().ToString())); } var result = new HttpRoutingResult(); result.ExecutionContext = this; switch (RouteExecuteType) { case ContextRoutingType.Single: { var host = TargetHostAddressList[0]; var hrm = getRequestMessage(host); var client = GetHttpClientForHost(host); var response = await client.SendAsync(hrm); result.SetResult(response); break; } case ContextRoutingType.FastestRoute: { var tasks = new List <Task <HttpResponseMessage> >(TargetHostAddressList.Count()); foreach (var host in TargetHostAddressList) { var client = GetHttpClientForHost(host); var hrm = getRequestMessage(host); tasks.Add(client.SendAsync(hrm)); } // TPL hoorah! var completedTask = await Task.WhenAny <HttpResponseMessage>(tasks); result.SetResult(await completedTask); break; } case ContextRoutingType.ScatterGather: { var tasks = new List <Task <HttpResponseMessage> >(TargetHostAddressList.Count()); foreach (var host in TargetHostAddressList) { var client = GetHttpClientForHost(host); var hrm = getRequestMessage(host); tasks.Add(client.SendAsync(hrm)); } await Task.WhenAll(tasks); var responses = new List <HttpResponseMessage>(TargetHostAddressList.Count()); foreach (var completedtask in tasks) { responses.Add(completedtask.Result); } result.SetResult(responses); break; } case ContextRoutingType.RoundRobin: { var host = GetNextHostAddressInBalancingSet(); var hrm = getRequestMessage(host); var client = GetHttpClientForHost(host); var response = await client.SendAsync(hrm); result.SetResult(response); break; } default: { throw new InvalidOperationException(string.Format("invalid routing type for http router", RouteExecuteType.ToString())); } } return(result); }