예제 #1
0
        public async Task SlowShutdownDoesntBlockUse()
        {
            var configuration = new ResourcePoolConfiguration()
            {
                MaximumAge = TimeSpan.FromSeconds(1),
                GarbageCollectionPeriod = Timeout.InfiniteTimeSpan,
            };

            var testTime = StopwatchSlim.Start();

            await RunTest <Key, SlowResource>(async (context, pool) =>
            {
                var key = new Key(0);

                var timeToStartup = StopwatchSlim.Start();
                await pool.UseAsync(context, key, wrapper =>
                {
                    timeToStartup.Elapsed.TotalSeconds.Should().BeLessThan(1);
                    return(BoolResult.SuccessTask);
                }).ShouldBeSuccess();
            },
                                              _ => new SlowResource(shutdownDelay: TimeSpan.FromSeconds(5)),
                                              configuration);

            // We should bear with shutdown slowness as we dispose the instance
            testTime.Elapsed.TotalSeconds.Should().BeGreaterOrEqualTo(4.9);
        }
예제 #2
0
        public async Task FailingShutdownDoesNotThrow()
        {
            CounterCollection <ResourcePoolV2Counters>?counters = null;

            var configuration = new ResourcePoolConfiguration()
            {
                MaximumAge = TimeSpan.FromSeconds(1),
                GarbageCollectionPeriod = Timeout.InfiniteTimeSpan,
            };

            await RunTest <Key, FailingResource>((context, pool) =>
            {
                counters = pool.Counter;

                var key = new Key(0);
                return(pool.UseAsync(context, key, wrapper =>
                {
                    return BoolResult.SuccessTask;
                }));
            },
                                                 _ => new FailingResource(shutdownFailure: true),
                                                 configuration);

            Contract.AssertNotNull(counters);

            counters[ResourcePoolV2Counters.ResourceInitializationAttempts].Value.Should().Be(1);
            counters[ResourcePoolV2Counters.ResourceInitializationFailures].Value.Should().Be(0);
            counters[ResourcePoolV2Counters.CreatedResources].Value.Should().Be(1);
            counters[ResourcePoolV2Counters.ReleasedResources].Value.Should().Be(1);
            counters[ResourcePoolV2Counters.ShutdownSuccesses].Value.Should().Be(0);
            counters[ResourcePoolV2Counters.ShutdownFailures].Value.Should().Be(1);
        }
예제 #3
0
        public Task GarbageCollectionRunsInTheBackground()
        {
            var configuration = new ResourcePoolConfiguration()
            {
                MaximumAge = TimeSpan.FromSeconds(1),
                GarbageCollectionPeriod = TimeSpan.FromSeconds(0.3),
            };

            return(RunTest <Key, Resource>(async(context, pool) =>
            {
                var key = new Key(0);
                var key1 = new Key(1);

                await pool.UseAsync(context, key, wrapper =>
                {
                    wrapper.Invalidate(context);
                    return BoolResult.SuccessTask;
                }).ShouldBeSuccess();

                await Task.Delay(TimeSpan.FromSeconds(1));

                pool.Counter[ResourcePoolV2Counters.ReleasedResources].Value.Should().Be(1);
                pool.Counter[ResourcePoolV2Counters.ShutdownSuccesses].Value.Should().Be(1);
                pool.Counter[ResourcePoolV2Counters.GarbageCollectionAttempts].Value.Should().BeGreaterOrEqualTo(1);
            },
                                           configuration));
        }
예제 #4
0
        public Task ReleasedInstancesArentRemovedIfTheyHaveAliveReferences()
        {
            var clock         = new MemoryClock();
            var configuration = new ResourcePoolConfiguration()
            {
                MaximumAge = TimeSpan.FromSeconds(1)
            };

            return(RunTest <Key, Resource>(async(context, pool) =>
            {
                var key = new Key(0);

                await pool.UseAsync(context, key, async wrapper =>
                {
                    // Invalidate resource. This will force GC to release it. Notice time doesn't change, so this isn't
                    // removed due to TTL
                    await pool.UseAsync(context, key, wrapper =>
                    {
                        wrapper.Invalidate(context);
                        return BoolResult.SuccessTask;
                    }).ShouldBeSuccess();

                    await pool.GarbageCollectAsync(context).IgnoreFailure();

                    wrapper.ShutdownToken.IsCancellationRequested.Should().BeTrue();
                    pool.Counter[ResourcePoolV2Counters.ReleasedResources].Value.Should().Be(1);
                    pool.Counter[ResourcePoolV2Counters.ShutdownAttempts].Value.Should().Be(0);

                    return BoolResult.Success;
                }).ShouldBeSuccess();
            },
                                           configuration,
                                           clock));
        }
예제 #5
0
        public Task ExpiredInstancesGetGarbageCollected()
        {
            var clock         = new MemoryClock();
            var configuration = new ResourcePoolConfiguration()
            {
                MaximumAge = TimeSpan.FromSeconds(1)
            };

            return(RunTest <Key, Resource>(async(context, pool) =>
            {
                var key = new Key(0);

                await pool.UseAsync(context, key, wrapper =>
                {
                    return BoolResult.SuccessTask;
                }).ShouldBeSuccess();

                clock.Increment(TimeSpan.FromMinutes(1));

                await pool.GarbageCollectAsync(context).IgnoreFailure();

                pool.Counter[ResourcePoolV2Counters.CreatedResources].Value.Should().Be(1);
                pool.Counter[ResourcePoolV2Counters.ReleasedResources].Value.Should().Be(1);
                pool.Counter[ResourcePoolV2Counters.ShutdownSuccesses].Value.Should().Be(1);
                pool.Counter[ResourcePoolV2Counters.GarbageCollectionSuccesses].Value.Should().Be(1);
            },
                                           configuration,
                                           clock));
        }
예제 #6
0
        public async Task FailingStartupThrowsResultPropagationException()
        {
            var configuration = new ResourcePoolConfiguration();

            await RunTest <Key, FailingResource>(async (context, pool) =>
            {
                _ = await Assert.ThrowsAsync <ResultPropagationException>(() =>
                {
                    return(pool.UseAsync(context, new Key(0), wrapper => BoolResult.SuccessTask));
                });
            },
                                                 _ => new FailingResource(startupFailure: true),
                                                 configuration);
        }
        /// <nodoc />
        public static GrpcCopyClientCacheConfiguration FromDistributedContentSettings(DistributedContentSettings dcs)
        {
            var grpcCopyClientConfiguration = GrpcCopyClientConfiguration.FromDistributedContentSettings(dcs);

            var resourcePoolConfiguration = ResourcePoolConfiguration.FromDistributedContentSettings(dcs);

            var grpcCopyClientCacheConfiguration = new GrpcCopyClientCacheConfiguration()
            {
                ResourcePoolConfiguration   = resourcePoolConfiguration,
                GrpcCopyClientConfiguration = grpcCopyClientConfiguration,
            };

            ApplyIfNotNull(dcs.GrpcCopyClientCacheResourcePoolVersion, v => grpcCopyClientCacheConfiguration.ResourcePoolVersion = (PoolVersion)v);

            return(grpcCopyClientCacheConfiguration);
        }
예제 #8
0
        public async Task FailingStartupThrowsOnThreadAndDoesntCache()
        {
            CounterCollection <ResourcePoolV2Counters>?counters = null;

            var configuration = new ResourcePoolConfiguration()
            {
                MaximumAge = TimeSpan.FromSeconds(1),
                GarbageCollectionPeriod = Timeout.InfiniteTimeSpan,
            };

            await RunTest <Key, FailingResource>(async (context, pool) =>
            {
                counters = pool.Counter;

                var key = new Key(0);

                _ = await Assert.ThrowsAsync <ResultPropagationException>(() =>
                {
                    return(pool.UseAsync <BoolResult>(context, key, wrapper =>
                    {
                        throw new NotImplementedException("This should not happen!");
                    }));
                });

                // This is just to ensure that retrying effectively does a retry
                _ = await Assert.ThrowsAsync <ResultPropagationException>(() =>
                {
                    return(pool.UseAsync <BoolResult>(context, key, wrapper =>
                    {
                        throw new NotImplementedException("This should not happen!");
                    }));
                });
            },
                                                 _ => new FailingResource(startupFailure: true),
                                                 configuration);

            Contract.AssertNotNull(counters);

            // We do 2 attempts to create a failing resource, so 4 total
            counters[ResourcePoolV2Counters.ResourceInitializationAttempts].Value.Should().Be(2);
            counters[ResourcePoolV2Counters.ResourceInitializationFailures].Value.Should().Be(2);
            counters[ResourcePoolV2Counters.CreatedResources].Value.Should().Be(2);
            counters[ResourcePoolV2Counters.ReleasedResources].Value.Should().Be(2);
        }
예제 #9
0
        public Task ExpiredInstancesGetReleasedOnReuse(bool invalidate)
        {
            var clock         = new MemoryClock();
            var configuration = new ResourcePoolConfiguration()
            {
                MaximumAge = TimeSpan.FromSeconds(1)
            };

            return(RunTest <Key, Resource>(async(context, pool) =>
            {
                var key = new Key(0);

                Resource?lastResource = null;
                await pool.UseAsync(context, key, wrapper =>
                {
                    if (invalidate)
                    {
                        wrapper.Invalidate(context);
                    }

                    lastResource = wrapper.Value;
                    return BoolResult.SuccessTask;
                }).ShouldBeSuccess();

                if (!invalidate)
                {
                    clock.Increment(TimeSpan.FromMinutes(1));
                }

                await pool.UseAsync(context, key, wrapper =>
                {
                    lastResource.Should().NotBe(wrapper.Value);
                    pool.Counter[ResourcePoolCounters.CreatedResources].Value.Should().Be(2);
                    pool.Counter[ResourcePoolCounters.ReleasedResources].Value.Should().Be(1);
                    return BoolResult.SuccessTask;
                }).ShouldBeSuccess();
            },
                                           configuration,
                                           clock));
        }
예제 #10
0
        public Task SlowStartupBlocksUseThread()
        {
            var configuration = new ResourcePoolConfiguration()
            {
                MaximumAge = TimeSpan.FromSeconds(1),
                GarbageCollectionPeriod = Timeout.InfiniteTimeSpan,
            };

            return(RunTest <Key, SlowResource>(async(context, pool) =>
            {
                var key = new Key(0);

                var timeToStartup = StopwatchSlim.Start();
                await pool.UseAsync(context, key, wrapper =>
                {
                    // Don't use 5s, because we may wake up slightly earlier than that
                    timeToStartup.Elapsed.TotalSeconds.Should().BeGreaterOrEqualTo(4.9);
                    return BoolResult.SuccessTask;
                }).ShouldBeSuccess();
            },
                                               _ => new SlowResource(startupDelay: TimeSpan.FromSeconds(5)),
                                               configuration));
        }