private void ScheduleForkIfNeeded(List <Task> currentTasks, Request request, IRequestTimeBudget budget, int currentReplicaIndex, int totalReplicas, CancellationToken cancellationToken)
        {
            if (currentReplicaIndex == totalReplicas - 1)
            {
                return;
            }

            if (currentTasks.Count >= maximumParallelism)
            {
                return;
            }

            var forkingDelay = delaysProvider.GetForkingDelay(request, budget, currentReplicaIndex, totalReplicas);

            if (forkingDelay == null)
            {
                return;
            }

            if (forkingDelay.Value < TimeSpan.Zero)
            {
                return;
            }

            if (forkingDelay.Value >= budget.Remaining)
            {
                return;
            }

            currentTasks.Add(delaysPlanner.Plan(forkingDelay.Value, cancellationToken));
        }
        public RequestContext(
            Request request,
            RequestParameters parameters,
            IRequestTimeBudget budget,
            ILog log,
            IClusterProvider clusterProvider,
            IReplicaOrdering replicaOrdering,
            ITransport transport,
            int maximumReplicasToUse,
            int connectionAttempts,
            string clientApplicationName        = null,
            CancellationToken cancellationToken = default)
        {
            Request               = request;
            Budget                = budget;
            Log                   = log;
            ClusterProvider       = clusterProvider;
            ReplicaOrdering       = replicaOrdering;
            Transport             = transport;
            Parameters            = parameters;
            CancellationToken     = cancellationToken;
            MaximumReplicasToUse  = maximumReplicasToUse;
            ConnectionAttempts    = connectionAttempts;
            ClientApplicationName = clientApplicationName;

            ResetReplicaResults();
        }
        private void LaunchRequest(List <Task> currentTasks, Request request, IRequestTimeBudget budget, IRequestSender sender, IEnumerator <Uri> replicasEnumerator, CancellationToken cancellationToken)
        {
            if (!replicasEnumerator.MoveNext())
            {
                throw new InvalidOperationException("Replicas enumerator ended prematurely. This is definitely a bug in code.");
            }

            currentTasks.Add(sender.SendToReplicaAsync(replicasEnumerator.Current, request, budget.Remaining, cancellationToken));
        }
        /// <inheritdoc />
        public TimeSpan GetTimeout(Request request, IRequestTimeBudget budget, int currentReplicaIndex, int totalReplicas)
        {
            if (currentReplicaIndex >= timeouts.Length)
            {
                return(tailBehaviour == TailTimeoutBehaviour.UseRemainingBudget
                    ? budget.Remaining
                    : TimeSpanArithmetics.Min(timeouts.Last(), budget.Remaining));
            }

            return(TimeSpanArithmetics.Min(timeouts[currentReplicaIndex], budget.Remaining));
        }
        private void LaunchRequest(List <Task> currentTasks, Request request, IRequestTimeBudget budget, IRequestSender sender, IEnumerator <Uri> replicasEnumerator, TimeSpan?connectionTimeout, CancellationToken cancellationToken)
        {
            if (!replicasEnumerator.MoveNext())
            {
                throw new InvalidOperationException("Replicas enumerator ended prematurely. This is definitely a bug in code.");
            }

            request = request.WithHeader(HeaderNames.ConcurrencyLevel, currentTasks.Count(task => task is Task <ReplicaResult>) + 1);

            currentTasks.Add(sender.SendToReplicaAsync(replicasEnumerator.Current, request, connectionTimeout, budget.Remaining, cancellationToken));
        }
Exemple #6
0
        public TimeSpan GetTimeout(Request request, IRequestTimeBudget budget, int currentReplicaIndex, int totalReplicas)
        {
            if (currentReplicaIndex >= providers.Length)
            {
                return(tailBehaviour == TailTimeoutBehaviour.UseRemainingBudget
                    ? budget.Remaining
                    : TimeSpanExtensions.Min(providers.Last()(), budget.Remaining));
            }

            return(TimeSpanExtensions.Min(providers[currentReplicaIndex](), budget.Remaining));
        }
        /// <inheritdoc />
        public TimeSpan GetTimeout(Request request, IRequestTimeBudget budget, int currentReplicaIndex, int totalReplicas)
        {
            if (currentReplicaIndex >= divisionFactor)
            {
                return(budget.Remaining);
            }

            var effectiveDivisionFactor = Math.Min(divisionFactor, totalReplicas) - currentReplicaIndex;

            return(TimeSpanArithmetics.Max(TimeSpan.Zero, budget.Remaining.Divide(effectiveDivisionFactor)));
        }
Exemple #8
0
        public ClusterResultStatus Select(IList <ReplicaResult> results, IRequestTimeBudget budget)
        {
            if (results.Any(result => result.Verdict == ResponseVerdict.Accept))
            {
                return(ClusterResultStatus.Success);
            }

            if (budget.HasExpired)
            {
                return(ClusterResultStatus.TimeExpired);
            }

            return(ClusterResultStatus.ReplicasExhausted);
        }
Exemple #9
0
        public async Task SendAsync(
            Request request,
            RequestParameters parameters,
            IRequestSender sender,
            IRequestTimeBudget budget,
            IEnumerable <Uri> replicas,
            int replicasCount,
            CancellationToken cancellationToken)
        {
            var requestPath         = GetRequestPath(request.Url);
            var requestIsIdempotent = await idempotencyIdentifier.IsIdempotentAsync(request.Method, requestPath).ConfigureAwait(false);

            var selectedStrategy = requestIsIdempotent ? forkingStrategy : sequential1Strategy;

            await selectedStrategy.SendAsync(request, parameters, sender, budget, replicas, replicasCount, cancellationToken).ConfigureAwait(false);
        }
 public Task SendAsync(
     Request request,
     RequestParameters parameters,
     IRequestSender sender,
     IRequestTimeBudget budget,
     IEnumerable <Uri> replicas,
     int replicasCount,
     CancellationToken cancellationToken)
 {
     return(sender.SendToReplicaAsync(
                replicas.Single(),
                request,
                parameters.ConnectionTimeout,
                budget.Remaining,
                cancellationToken));
 }
        public async Task SendAsync(Request request, IRequestSender sender, IRequestTimeBudget budget, IEnumerable <Uri> replicas, int replicasCount, CancellationToken cancellationToken)
        {
            var initialRequestCount = Math.Min(parallelismLevel, replicasCount);
            var currentTasks        = new List <Task <ReplicaResult> >(initialRequestCount);

            using (var localCancellationSource = new CancellationTokenSource())
                using (var linkedCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, localCancellationSource.Token))
                {
                    var linkedCancellationToken = linkedCancellationSource.Token;

                    using (var replicasEnumerator = replicas.GetEnumerator())
                    {
                        for (var i = 0; i < initialRequestCount; i++)
                        {
                            if (!replicasEnumerator.MoveNext())
                            {
                                throw new InvalidOperationException("Replicas enumerator ended prematurely. This is definitely a bug in code.");
                            }

                            currentTasks.Add(sender.SendToReplicaAsync(replicasEnumerator.Current, request, budget.Remaining, linkedCancellationToken));
                        }

                        while (currentTasks.Count > 0)
                        {
                            var completedTask = await Task.WhenAny(currentTasks).ConfigureAwait(false);

                            currentTasks.Remove(completedTask);

                            var completedResult = await completedTask.ConfigureAwait(false);

                            if (completedResult.Verdict == ResponseVerdict.Accept)
                            {
                                localCancellationSource.Cancel();
                                return;
                            }

                            cancellationToken.ThrowIfCancellationRequested();

                            if (replicasEnumerator.MoveNext())
                            {
                                currentTasks.Add(sender.SendToReplicaAsync(replicasEnumerator.Current, request, budget.Remaining, linkedCancellationToken));
                            }
                        }
                    }
                }
        }
Exemple #12
0
        public void TestSetup()
        {
            replicas = new[]
            {
                new Uri("http://host1/"),
                new Uri("http://host2/")
            };

            request    = Request.Get("foo/bar");
            budget     = Budget.WithRemaining(5.Minutes());
            parameters = RequestParameters.Empty.WithConnectionTimeout(1.Seconds());
            result     = new ReplicaResult(replicas[0], new Response(ResponseCode.NotFound), ResponseVerdict.Accept, TimeSpan.Zero);

            sender = Substitute.For <IRequestSender>();
            sender.SendToReplicaAsync(null, null, parameters.ConnectionTimeout, TimeSpan.Zero, Arg.Any <CancellationToken>()).ReturnsForAnyArgs(_ => result);

            strategy = new SingleReplicaRequestStrategy();
        }
        /// <inheritdoc />
        public TimeSpan?GetForkingDelay(Request request, IRequestTimeBudget budget, int currentReplicaIndex, int totalReplicas)
        {
            if (currentReplicaIndex < delays.Length)
            {
                return(delays[currentReplicaIndex]);
            }

            switch (tailBehaviour)
            {
            case TailDelayBehaviour.RepeatLastValue:
                return(delays.Last());

            case TailDelayBehaviour.RepeatAllValues:
                return(delays[currentReplicaIndex % delays.Length]);

            default:
                return(null);
            }
        }
        public void SetUp()
        {
            replicas = new[]
            {
                new Uri("http://host1/"),
                new Uri("http://host2/")
            };

            request = Request.Get("foo/bar");
            budget  = Budget.WithRemaining(5.Minutes());
            result  = new ReplicaResult(replicas[0], new Response(ResponseCode.NotFound), ResponseVerdict.Accept, TimeSpan.Zero);

            sender = Substitute.For <IRequestSender>();
            // ReSharper disable AssignNullToNotNullAttribute
            sender.SendToReplicaAsync(null, null, TimeSpan.Zero, Arg.Any <CancellationToken>()).ReturnsForAnyArgs(_ => result);
            // ReSharper restore AssignNullToNotNullAttribute

            strategy = new SingleReplicaRequestStrategy();
        }
        public RequestContext(
            Request request,
            IRequestStrategy strategy,
            IRequestTimeBudget budget,
            ILog log,
            CancellationToken cancellationToken,
            RequestPriority?priority,
            int maximumReplicasToUse)
        {
            Request              = request;
            Strategy             = strategy;
            Budget               = budget;
            Log                  = log;
            Priority             = priority;
            CancellationToken    = cancellationToken;
            MaximumReplicasToUse = maximumReplicasToUse;

            ResetReplicaResults();
        }
        public async Task SendAsync(Request request, IRequestSender sender, IRequestTimeBudget budget, IEnumerable <Uri> replicas, int replicasCount, CancellationToken cancellationToken)
        {
            var currentTasks = new List <Task>(Math.Min(maximumParallelism, replicasCount));

            using (var localCancellationSource = new CancellationTokenSource())
                using (var linkedCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, localCancellationSource.Token))
                {
                    var linkedCancellationToken = linkedCancellationSource.Token;

                    using (var replicasEnumerator = replicas.GetEnumerator())
                    {
                        for (var i = 0; i < replicasCount; i++)
                        {
                            if (budget.HasExpired)
                            {
                                break;
                            }

                            LaunchRequest(currentTasks, request, budget, sender, replicasEnumerator, linkedCancellationToken);

                            ScheduleForkIfNeeded(currentTasks, request, budget, i, replicasCount, linkedCancellationToken);

                            if (await WaitForAcceptedResultAsync(currentTasks).ConfigureAwait(false))
                            {
                                localCancellationSource.Cancel();
                                return;
                            }

                            cancellationToken.ThrowIfCancellationRequested();
                        }
                    }

                    while (currentTasks.Count > 0)
                    {
                        if (budget.HasExpired || await WaitForAcceptedResultAsync(currentTasks).ConfigureAwait(false))
                        {
                            return;
                        }
                    }
                }
        }
        public RequestContext(
            Request request,
            RequestParameters parameters,
            IRequestTimeBudget budget,
            ILog log,
            ITransport transport,
            int maximumReplicasToUse,
            string clientApplicationName        = null,
            CancellationToken cancellationToken = default)
        {
            Request               = request;
            Budget                = budget;
            Log                   = log;
            Transport             = transport;
            Parameters            = parameters;
            CancellationToken     = cancellationToken;
            MaximumReplicasToUse  = maximumReplicasToUse;
            ClientApplicationName = clientApplicationName;

            ResetReplicaResults();
        }
        public async Task SendAsync(Request request, IRequestSender sender, IRequestTimeBudget budget, IEnumerable <Uri> replicas, int replicasCount, CancellationToken cancellationToken)
        {
            var currentReplicaIndex = 0;

            foreach (var replica in replicas)
            {
                if (budget.HasExpired)
                {
                    break;
                }

                var timeout = TimeSpanExtensions.Min(timeoutsProvider.GetTimeout(request, budget, currentReplicaIndex++, replicasCount), budget.Remaining);

                var result = await sender.SendToReplicaAsync(replica, request, timeout, cancellationToken).ConfigureAwait(false);

                if (result.Verdict == ResponseVerdict.Accept)
                {
                    break;
                }

                cancellationToken.ThrowIfCancellationRequested();
            }
        }
        /// <inheritdoc />
        public async Task SendAsync(Request request, RequestParameters parameters, IRequestSender sender, IRequestTimeBudget budget, IEnumerable <Uri> replicas, int replicasCount, CancellationToken cancellationToken)
        {
            var currentReplicaIndex = 0;

            foreach (var replica in replicas)
            {
                if (budget.HasExpired)
                {
                    break;
                }

                if (request.ContainsAlreadyUsedStream())
                {
                    break;
                }

                var timeout = TimeSpanArithmetics.Min(timeoutsProvider.GetTimeout(request, budget, currentReplicaIndex++, replicasCount), budget.Remaining);

                var connectionAttemptTimeout = currentReplicaIndex == replicasCount ? null : parameters.ConnectionTimeout;

                var result = await sender.SendToReplicaAsync(replica, request, connectionAttemptTimeout, timeout, cancellationToken).ConfigureAwait(false);

                if (result.Verdict == ResponseVerdict.Accept)
                {
                    break;
                }

                cancellationToken.ThrowIfCancellationRequested();
            }
        }
 public Task SendAsync(Request request, IRequestSender sender, IRequestTimeBudget budget, IEnumerable <Uri> replicas, int replicasCount, CancellationToken cancellationToken)
 {
     throw new NotImplementedException();
 }
Exemple #21
0
 /// <inheritdoc />
 public TimeSpan?GetForkingDelay(Request request, IRequestTimeBudget budget, int currentReplicaIndex, int totalReplicas) =>
 budget.Total.Divide(Math.Min(divisionFactor, totalReplicas));
 public TimeSpan GetTimeout(Request request, IRequestTimeBudget budget, int currentReplicaIndex, int totalReplicas)
 {
     return(currentReplicaIndex < fixedTimeoutsCount
         ? adHocProvider.GetTimeout(request, budget, currentReplicaIndex, totalReplicas)
         : equalProvider.GetTimeout(request, budget, currentReplicaIndex - fixedTimeoutsCount, totalReplicas));
 }
Exemple #23
0
 public Task SendAsync(Request request, IRequestSender sender, IRequestTimeBudget budget, IEnumerable <Uri> replicas, int replicasCount, CancellationToken cancellationToken)
 {
     return(sender.SendToReplicaAsync(replicas.First(), request, budget.Remaining, cancellationToken));
 }
 private void Send(IRequestTimeBudget budget)
 {
     strategy.SendAsync(request, parameters, sender, budget, replicas, replicas.Length, token).GetAwaiter().GetResult();
 }
        public Task SendAsync(Request request, RequestParameters parameters, IRequestSender sender, IRequestTimeBudget budget,
                              IEnumerable <Uri> replicas, int replicasCount, CancellationToken cancellationToken)
        {
            var senderWithLatency = new LatencyRequestSender(sender, latencyPerformer, rateManager, latencyProvider(), rateProvider());

            return(baseStrategy.SendAsync(request, parameters, senderWithLatency, budget, replicas, replicasCount, cancellationToken));
        }
 /// <inheritdoc />
 public Task SendAsync(Request request, RequestParameters parameters, IRequestSender sender, IRequestTimeBudget budget, IEnumerable <Uri> replicas, int replicasCount, CancellationToken cancellationToken) =>
 sender.SendToReplicaAsync(replicas.First(), request, null, budget.Remaining, cancellationToken);
 public TimeSpan?GetForkingDelay(Request request, IRequestTimeBudget budget, int currentReplicaIndex, int totalReplicas)
 {
     return(currentReplicaIndex < fixedDelaysCount
         ? adHocProvider.GetForkingDelay(request, budget, currentReplicaIndex, totalReplicas)
         : equalProvider.GetForkingDelay(request, budget, currentReplicaIndex, totalReplicas));
 }
        private static void TryLaunchNextRequest(Request request, IRequestSender sender, IRequestTimeBudget budget, IEnumerator <Uri> replicas, List <Task <ReplicaResult> > currentTasks, TimeSpan?connectionTimeout, CancellationToken cancellationToken)
        {
            if (budget.HasExpired)
            {
                return;
            }

            if (request.ContainsAlreadyUsedStream() || request.ContainsAlreadyUsedContent())
            {
                return;
            }

            if (replicas.MoveNext())
            {
                currentTasks.Add(sender.SendToReplicaAsync(replicas.Current, request, connectionTimeout, budget.Remaining, cancellationToken));
            }
        }