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); }
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); }
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)); }
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)); }
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)); }
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); }
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); }
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)); }
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)); }