public virtual INodeService AddNode(EnhancedServiceParams serviceParams, int weight = 1) { serviceParams.Require(nameof(serviceParams), "Service Parameters must be set first."); weight.RequireAtLeast(1, nameof(weight)); var node = new NodeService(serviceParams, weight); if (NodeQueue.IsEmpty) { SetPrimaryNode(node); } NodeQueue.Enqueue(node); return(node); }
public virtual IEnhancedOrgService GetService(int threads = 1) { threads.RequireAtLeast(1); ValidateState(); NodeService node = null; lock (dequeueLock) { while (true) { switch (Rules.RouterMode) { case RouterMode.RoundRobin: case null: foreach (var _ in NodeQueue) { NodeQueue.TryDequeue(out node); NodeQueue.Enqueue(node); if (node.Status == NodeStatus.Online) { break; } } break; case RouterMode.WeightedRoundRobin: foreach (var _ in NodeQueue) { var currentNode = NodeQueue.FirstOrDefault(); var latestNode = NodeQueue.LastOrDefault(); var currentNodeExecutions = currentNode?.Pool.Stats.RequestCount; var latestNodeExecutions = latestNode?.Pool.Stats.RequestCount; if (currentNode?.Status == NodeStatus.Online && (currentNodeExecutions / (double?)latestNodeExecutions) < (currentNode?.Weight / (double?)latestNode?.Weight)) { node = currentNode; } else { NodeQueue.TryDequeue(out node); NodeQueue.Enqueue(node); node = NodeQueue.FirstOrDefault(); } if (node?.Status == NodeStatus.Online) { break; } } break; case RouterMode.StaticWithFallback: node = NodeQueue.FirstOrDefault(n => n.IsPrimary) ?? NodeQueue.FirstOrDefault(n => n.Status == NodeStatus.Online); break; case RouterMode.LeastLoaded: node = NodeQueue .Select(n => new { n, load = n.Pool.Stats.PendingOperations .Count(o => o.OperationStatus != Status.Success && o.OperationStatus != Status.Failure) }) .Where(e => e.n.Status == NodeStatus.Online) .OrderBy(e => e.load) .FirstOrDefault()?.n; break; case RouterMode.LeastLatency: node = NodeQueue .Where(n => n.Status == NodeStatus.Online) .OrderBy(n => n.Latency).FirstOrDefault(); break; default: throw new ArgumentOutOfRangeException(nameof(Rules.RouterMode), Rules.RouterMode, "Router mode is not supported."); } if (Rules.IsFallbackEnabled == true) { node ??= FallbackNodes.OfType <NodeService>().Union(NodeQueue).FirstOrDefault(n => n.Status == NodeStatus.Online); } // if no nodes found and there is a node with no latency measured (starting up), wait if (node == null && NodeQueue.Union(FallbackNodes.OfType <NodeService>()).Any(n => !n.LatencyHistory.Any())) { Thread.Sleep(100); continue; } break; } } if (node == null) { throw new NodeSelectException("Cannot find a valid node."); } var service = node.Pool.GetService(threads); if (service.Parameters.AutoRetryParams?.CustomRetryFunctions.Contains(CustomRetry) == false) { service.Parameters.AutoRetryParams.CustomRetryFunctions?.Add(CustomRetry); } return(service); }