public async Task TestStorageConcurrence(Type storageProviderType) { IStorageProvider store; switch (storageProviderType.Name) { case nameof(BlobStorageProvider): var blobServiceClient = new BlobServiceClient("UseDevelopmentStorage=true"); var container = blobServiceClient.GetBlobContainerClient("globalcache"); await container.CreateIfNotExistsAsync(); store = new BlobStorageProvider(container); break; case nameof(FileStorageProvider): store = new FileStorageProvider(); break; default: throw new NotSupportedException($"{nameof(storageProviderType)} is not supported"); } var id = new CacheId("concurrence", 1); var str = "hello world" + Guid.NewGuid(); var writes = 0; await store.RemoveAsync(id); await Task.WhenAll(new [] { GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), store.RemoveAsync(id), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), store.RemoveAsync(id), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), store.RemoveAsync(id), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), GetOrCreateAsync().ContinueWith(task => Assert.Equal(str, task.Result)), }); // await store.RemoveAsync(id); async Task <string> GetOrCreateAsync() { var retries = new RetryHelper(1, 500, totalMaxDelay: TimeSpan.FromSeconds(60)); do { if (await store.TryOpenRead(id) is Stream readStream) { using (readStream) { using var sr = new StreamReader(readStream); return(await sr.ReadToEndAsync()); } } if (await store.TryOpenWrite(id) is StreamWithCompletion writeStream) { using (writeStream) { // !!!!Expensive data generation here!!!! await writeStream.WriteAsync(Encoding.Default.GetBytes(str !)); Interlocked.Increment(ref writes); // !!!! } await writeStream; return(str !); } if (await retries.DelayAsync().ConfigureAwait(false) == false) { throw new TimeoutException(); } }while (true); } }