From c0f3edb4a8d3f0c9548a4c28655f4c721027b545 Mon Sep 17 00:00:00 2001 From: "TRGDEV\\iboyko" Date: Tue, 18 Sep 2018 23:58:40 +0300 Subject: [PATCH] A cancellation doesn't work in some cases and a deadlock may occure. I added an additional cancellation. --- src/Docker.DotNet/Endpoints/StreamUtil.cs | 18 ++++++++++++++++-- .../ISystemOperations.Tests.cs | 11 +++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Docker.DotNet/Endpoints/StreamUtil.cs b/src/Docker.DotNet/Endpoints/StreamUtil.cs index e2ce954c1..4b7d19046 100644 --- a/src/Docker.DotNet/Endpoints/StreamUtil.cs +++ b/src/Docker.DotNet/Endpoints/StreamUtil.cs @@ -19,7 +19,7 @@ internal static async Task MonitorStreamAsync(Task streamTask, DockerCli using (var reader = new StreamReader(stream, new UTF8Encoding(false))) { string line; - while ((line = await reader.ReadLineAsync()) != null) + while ((line = await reader.ReadLineAsync().WithCancellation(cancel)) != null) { progress.Report(line); } @@ -40,7 +40,7 @@ internal static async Task MonitorStreamForMessagesAsync(Task streamT string line; try { - while ((line = await reader.ReadLineAsync()) != null) + while ((line = await reader.ReadLineAsync().WithCancellation(cancel)) != null) { var prog = client.JsonSerializer.DeserializeObject(line); if (prog == null) continue; @@ -57,5 +57,19 @@ internal static async Task MonitorStreamForMessagesAsync(Task streamT } } } + + private static async Task WithCancellation(this Task task, CancellationToken cancellationToken) + { + var tcs = new TaskCompletionSource(); + using (cancellationToken.Register(s => ((TaskCompletionSource)s).TrySetResult(true), tcs)) + { + if (task != await Task.WhenAny(task, tcs.Task)) + { + throw new OperationCanceledException(cancellationToken); + } + } + + return await task; + } } } \ No newline at end of file diff --git a/test/Docker.DotNet.Tests/ISystemOperations.Tests.cs b/test/Docker.DotNet.Tests/ISystemOperations.Tests.cs index ac5a73372..e32a50ddd 100644 --- a/test/Docker.DotNet.Tests/ISystemOperations.Tests.cs +++ b/test/Docker.DotNet.Tests/ISystemOperations.Tests.cs @@ -90,6 +90,17 @@ public async Task MonitorEventsAsync_Succeeds() await _client.Images.DeleteImageAsync($"{repository}:{tag}", new ImageDeleteParameters()); } + [Fact] + public async Task MonitorEventsAsync_EmptyContainersList_CanBeCancelled() + { + var cts = new CancellationTokenSource(); + + cts.CancelAfter(1000); + var task = _client.System.MonitorEventsAsync(new ContainerEventsParameters(), new Progress(), cts.Token); + + await Assert.ThrowsAsync(async () => await task); + } + class Progress : IProgress { internal Action _onCalled;