コード例 #1
0
    public async Task ManyWaitsStackUp()
    {
        await Policy
        .Handle <InRangeException>()
        .RetryAsync(3)
        .ExecuteAsync(async() =>
        {
            var limiter            = new Limiter(new Limit(10), 5);
            using var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(5));

            while (cancellation.IsCancellationRequested == false)
            {
                var task = limiter.WaitAsync(cancellation.Token);
                if (!task.IsCompleted)
                {
                    await task.ConfigureAwait(false);
                    break;
                }
            }

            var delayOne = new Stopwatch();
            delayOne.Start();

            var delayTwo = new Stopwatch();
            delayTwo.Start();

            var delayThree = new Stopwatch();
            delayThree.Start();

            var waits = new List <Task>
            {
                limiter.WaitAsync(cancellation.Token),
                limiter.WaitAsync(cancellation.Token),
                limiter.WaitAsync(cancellation.Token),
            };

            var taskOne = await Task.WhenAny(waits).ConfigureAwait(false);
            await taskOne.ConfigureAwait(false);
            delayOne.Stop();
            waits.Remove(taskOne);

            var taskTwo = await Task.WhenAny(waits).ConfigureAwait(false);
            await taskTwo.ConfigureAwait(false);
            delayTwo.Stop();
            waits.Remove(taskTwo);

            var taskThree = await Task.WhenAny(waits).ConfigureAwait(false);
            await taskThree.ConfigureAwait(false);
            delayThree.Stop();
            waits.Remove(taskThree);

            Assert.InRange(delayOne.Elapsed, TimeSpan.FromMilliseconds(75), TimeSpan.FromMilliseconds(125));
            Assert.InRange(delayTwo.Elapsed, TimeSpan.FromMilliseconds(175), TimeSpan.FromMilliseconds(225));
            Assert.InRange(delayThree.Elapsed, TimeSpan.FromMilliseconds(275), TimeSpan.FromMilliseconds(325));
        }).ConfigureAwait(false);
    }
コード例 #2
0
    public async Task WaitAsyncCausesPauseLikeReserve()
    {
        var limiter = new Limiter(new Limit(10), 5);

        using var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(5));

        while (cancellation.IsCancellationRequested == false)
        {
            var task = limiter.WaitAsync(cancellation.Token);
            if (!task.IsCompleted)
            {
                await task.ConfigureAwait(false);

                break;
            }
        }

        var delayOne = new Stopwatch();

        delayOne.Start();
        await limiter.WaitAsync(cancellation.Token).ConfigureAwait(false);

        delayOne.Stop();

        var delayTwoMore = new Stopwatch();

        delayTwoMore.Start();
        await limiter.WaitAsync(2, cancellation.Token).ConfigureAwait(false);

        delayTwoMore.Stop();

        await Task.Delay(TimeSpan.FromMilliseconds(150)).ConfigureAwait(false);

        var delayAlreadyAvailable = new Stopwatch();

        delayAlreadyAvailable.Start();
        await limiter.WaitAsync(cancellation.Token).ConfigureAwait(false);

        delayAlreadyAvailable.Stop();

        var delayHalfAvailable = new Stopwatch();

        delayHalfAvailable.Start();
        await limiter.WaitAsync(cancellation.Token).ConfigureAwait(false);

        delayHalfAvailable.Stop();

        Assert.InRange(delayOne.Elapsed, TimeSpan.FromMilliseconds(75), TimeSpan.FromMilliseconds(125));
        Assert.InRange(delayTwoMore.Elapsed, TimeSpan.FromMilliseconds(175), TimeSpan.FromMilliseconds(225));
        Assert.InRange(delayAlreadyAvailable.Elapsed, TimeSpan.Zero, TimeSpan.FromMilliseconds(5));
        Assert.InRange(delayHalfAvailable.Elapsed, TimeSpan.FromMilliseconds(25), TimeSpan.FromMilliseconds(75));
    }
コード例 #3
0
ファイル: LimiterTests.cs プロジェクト: vchirikov/limiter
        public async Task WaitAsync_Should_StopTimeDelayOnCancel()
        {
            using var cts = new CancellationTokenSource();
            var limiter = new Limiter(1, TimeSpan.FromSeconds(10), SystemTime.Instance);

            await limiter.WaitAsync(cts.Token).ConfigureAwait(false);

            var task = limiter.WaitAsync(cts.Token);

            cts.Cancel();

            await Assert.ThrowsAsync <OperationCanceledException>(async() => await task.ConfigureAwait(false)).ConfigureAwait(false);
        }
コード例 #4
0
ファイル: LimiterTests.cs プロジェクト: vchirikov/limiter
        public async Task WaitAsync_Should_StopLockingOnCancel()
        {
            using var cts = new CancellationTokenSource();
            var time = A.Fake <ITime>();
            var date = new DateTimeOffset(new DateTime(2000, 1, 1), default);

            A.CallTo(() => time.UtcNow).Returns(date);
            A.CallTo(() => time.Delay(A <TimeSpan> ._, A <CancellationToken> ._))
            .ReturnsLazily(call => Task.Delay(20_000, (CancellationToken)call.Arguments[1]));

            var limiter = new Limiter(1, TimeSpan.FromSeconds(10), time);

            await limiter.WaitAsync(cts.Token).ConfigureAwait(false);

            var waitTaskOnDelay = limiter.WaitAsync(cts.Token);

            var taskWaitOnLock = limiter.WaitAsync(cts.Token);

            cts.Cancel();

            await Assert.ThrowsAsync <OperationCanceledException>(async() => await taskWaitOnLock.ConfigureAwait(false)).ConfigureAwait(false);
        }
コード例 #5
0
ファイル: Receiver.cs プロジェクト: ManickaP/reverse-proxy
        public override async Task RunAsync(CancellationToken cancellationToken)
        {
            using var client = new HttpClient();

            while (!cancellationToken.IsCancellationRequested)
            {
                await _limiter.WaitAsync(cancellationToken).ConfigureAwait(false);

#pragma warning disable CA1303 // Do not pass literals as localized parameters
                Logger.LogInformation("Connecting with {ControllerUrl}", _options.ControllerUrl.ToString());

                try
                {
#if NET
                    using var stream = await client.GetStreamAsync(_options.ControllerUrl, cancellationToken).ConfigureAwait(false);
#else
                    using var stream = await client.GetStreamAsync(_options.ControllerUrl).ConfigureAwait(false);
#endif
                    using var reader       = new StreamReader(stream, Encoding.UTF8, leaveOpen: true);
                    using var cancellation = cancellationToken.Register(stream.Close);
                    while (true)
                    {
                        var json = await reader.ReadLineAsync().ConfigureAwait(false);

                        if (string.IsNullOrEmpty(json))
                        {
                            break;
                        }

                        var message = System.Text.Json.JsonSerializer.Deserialize <Message>(json);
                        Logger.LogInformation("Received {MessageType} for {MessageKey}", message.MessageType, message.Key);

                        Logger.LogInformation(json);
                        Logger.LogInformation(message.MessageType.ToString());

                        if (message.MessageType == MessageType.Update)
                        {
                            _proxyConfigProvider.Update(message.Routes, message.Cluster);
                        }
                    }
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    Logger.LogInformation("Stream ended: {Message}", ex.Message);
                }
#pragma warning restore CA1303 // Do not pass literals as localized parameters
            }
        }
コード例 #6
0
ファイル: LimiterTests.cs プロジェクト: vchirikov/limiter
        public async Task WaitAsync_Should_ReturnWithDelayIfSlotsAreFilled()
        {
            int maxCount = 5;
            var interval = TimeSpan.FromMinutes(3);
            var time     = A.Fake <ITime>();
            var date     = new DateTimeOffset(new DateTime(2000, 1, 1), default);

            A.CallTo(() => time.UtcNow).Returns(date);

            var limiter = new Limiter(maxCount, interval, time);
            var tasks   = Enumerable.Range(0, maxCount).Select(x => limiter.WaitAsync());

            var delay = Task.Delay(1_000);

            if (delay == await Task.WhenAny(delay, Task.WhenAll(tasks)).ConfigureAwait(false))
            {
                throw new TimeoutException("Limiter too slow and didn't return slots");
            }

            await limiter.WaitAsync().ConfigureAwait(false);

            A.CallTo(() => time.UtcNow).MustHaveHappened(maxCount + 1, Times.Exactly);
            A.CallTo(() => time.Delay(A <TimeSpan> .That.IsEqualTo(interval), A <CancellationToken> ._)).MustHaveHappenedOnceExactly();
        }
コード例 #7
0
ファイル: LimiterTests.cs プロジェクト: vchirikov/limiter
        public async Task WaitAsync_Should_ReturnWithoutDelayIfSlotsAreEmpty()
        {
            int maxCount = 3;
            var interval = TimeSpan.FromMinutes(3);
            var time     = A.Fake <ITime>();

            A.CallTo(() => time.UtcNow).Returns(new DateTimeOffset(new DateTime(2000, 1, 1), default));

            var limiter = new Limiter(maxCount, interval, time);

            await limiter.WaitAsync().ConfigureAwait(false);

            A.CallTo(() => time.UtcNow).MustHaveHappenedOnceExactly();
            A.CallTo(() => time.Delay(A <TimeSpan> ._, A <CancellationToken> ._)).MustNotHaveHappened();
        }
コード例 #8
0
ファイル: Receiver.cs プロジェクト: endless001/Sail
        public override async Task RunAsync(CancellationToken cancellationToken)
        {
            using var client = new HttpClient();

            while (!cancellationToken.IsCancellationRequested)
            {
                await _limiter.WaitAsync(cancellationToken).ConfigureAwait(false);

                Logger.LogInformation($"Connecting with { _options.ControllerUrl.ToString()}");

                try
                {
                    using var stream = await client.GetStreamAsync(_options.ControllerUrl, cancellationToken).ConfigureAwait(false);

                    using var reader       = new StreamReader(stream, Encoding.UTF8, leaveOpen: true);
                    using var cancellation = cancellationToken.Register(stream.Close);
                    while (true)
                    {
                        var json = await reader.ReadLineAsync().ConfigureAwait(false);

                        if (string.IsNullOrEmpty(json))
                        {
                            break;
                        }

                        var message = JsonSerializer.Deserialize <Message>(json);
                        Logger.LogInformation($"Received {message.MessageType} for { message.Key}");

                        Logger.LogInformation(json);
                        Logger.LogInformation(message.MessageType.ToString());

                        if (message.MessageType == MessageType.Update)
                        {
                            _proxyConfigProvider.Update(message.Routes, message.Cluster);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogInformation($"Stream ended: { ex.Message}");
                }
            }
        }
コード例 #9
0
        /// <summary>
        /// RunAsync starts processing when StartAsync is called, and is terminated when
        /// StopAsync is called.
        /// </summary>
        /// <param name="cancellationToken">The cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
        public override async Task RunAsync(CancellationToken cancellationToken)
        {
            try
            {
                var limiter    = new Limiter(new Limit(0.2), 3);
                var shouldSync = true;
                var firstSync  = true;
                while (true)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    try
                    {
                        if (shouldSync)
                        {
                            await ListAsync(cancellationToken).ConfigureAwait(true);

                            shouldSync = false;
                        }

                        if (firstSync)
                        {
                            _ready.Release();
                            firstSync = false;
                        }

                        await WatchAsync(cancellationToken).ConfigureAwait(true);
                    }
                    catch (IOException ex) when(ex.InnerException is SocketException)
                    {
                        Logger.LogDebug(
                            EventId(EventType.ReceivedError),
                            "Received error watching {ResourceType}: {ErrorMessage}",
                            typeof(TResource).Name,
                            ex.Message);
                    }
                    catch (KubernetesException ex)
                    {
                        Logger.LogDebug(
                            EventId(EventType.ReceivedError),
                            "Received error watching {ResourceType}: {ErrorMessage}",
                            typeof(TResource).Name,
                            ex.Message);

                        // deal with this non-recoverable condition "too old resource version"
                        // with a re-sync to listing everything again ensuring no subscribers miss updates
                        if (ex is KubernetesException kubernetesError)
                        {
                            if (string.Equals(kubernetesError.Status.Reason, "Expired", StringComparison.Ordinal))
                            {
                                shouldSync = true;
                            }
                        }
                    }

                    // rate limiting the reconnect loop
                    await limiter.WaitAsync(cancellationToken).ConfigureAwait(true);
                }
            }
            catch (Exception error)
            {
                Logger.LogInformation(
                    EventId(EventType.WatchingComplete),
                    error,
                    "No longer watching {ResourceType} resources from API server.",
                    typeof(TResource).Name);
                throw;
            }
        }