fix hangs due to uncleared TCS in IntegrationTesting (#1008)
This commit is contained in:
parent
39164eeb40
commit
ad79cdd123
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace System.Threading.Tasks
|
||||
{
|
||||
internal static class TaskTimeoutExtensions
|
||||
{
|
||||
public static async Task OrTimeout(this Task task, TimeSpan timeout)
|
||||
{
|
||||
var completed = await Task.WhenAny(task, Task.Delay(timeout));
|
||||
if (completed == task)
|
||||
{
|
||||
// Manifest any exception
|
||||
task.GetAwaiter().GetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<T> OrTimeout<T>(this Task<T> task, TimeSpan timeout)
|
||||
{
|
||||
var completed = await Task.WhenAny(task, Task.Delay(timeout));
|
||||
if (completed == task)
|
||||
{
|
||||
return await task;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ using System.Text.RegularExpressions;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||
|
|
@ -213,6 +214,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
process.Exited += (sender, e) =>
|
||||
{
|
||||
Logger.LogInformation("iisexpress Process {pid} shut down", process.Id);
|
||||
|
||||
// If TrySetResult was called above, this will just silently fail to set the new state, which is what we want
|
||||
started.TrySetException(new Exception($"Command exited unexpectedly with exit code: {process.ExitCode}"));
|
||||
|
||||
TriggerHostShutdown(hostExitTokenSource);
|
||||
};
|
||||
process.StartAndCaptureOutAndErrToLogger("iisexpress", Logger);
|
||||
|
|
@ -225,7 +230,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
}
|
||||
|
||||
// Wait for the app to start
|
||||
if (!await started.Task)
|
||||
// The timeout here is large, because we don't know how long the test could need
|
||||
// We cover a lot of error cases above, but I want to make sure we eventually give up and don't hang the build
|
||||
// just in case we missed one -anurse
|
||||
if (!await started.Task.TimeoutAfter(TimeSpan.FromMinutes(10)))
|
||||
{
|
||||
Logger.LogInformation("iisexpress Process {pid} failed to bind to port {port}, trying again", _hostProcess.Id, port);
|
||||
|
||||
|
|
@ -294,10 +302,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
|
||||
// If by this point, the host process is still running (somehow), throw an error.
|
||||
// A test failure is better than a silent hang and unknown failure later on
|
||||
if(!_hostProcess.HasExited)
|
||||
if (!_hostProcess.HasExited)
|
||||
{
|
||||
throw new Exception($"iisexpress Process {_hostProcess.Id} failed to shutdown");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using System.Text.RegularExpressions;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||
|
|
@ -140,6 +141,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
HostProcess.Exited += (sender, e) =>
|
||||
{
|
||||
Logger.LogInformation("host process ID {pid} shut down", HostProcess.Id);
|
||||
|
||||
// If TrySetResult was called above, this will just silently fail to set the new state, which is what we want
|
||||
started.TrySetException(new Exception($"Command exited unexpectedly with exit code: {HostProcess.ExitCode}"));
|
||||
|
||||
TriggerHostShutdown(hostExitTokenSource);
|
||||
};
|
||||
|
||||
|
|
@ -160,7 +165,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
|
||||
Logger.LogInformation("Started {fileName}. Process Id : {processId}", startInfo.FileName, HostProcess.Id);
|
||||
|
||||
await started.Task;
|
||||
// The timeout here is large, because we don't know how long the test could need
|
||||
// We cover a lot of error cases above, but I want to make sure we eventually give up and don't hang the build
|
||||
// just in case we missed one -anurse
|
||||
await started.Task.TimeoutAfter(TimeSpan.FromMinutes(10));
|
||||
|
||||
return (url: actualUrl ?? hintUrl, hostExitToken: hostExitTokenSource.Token);
|
||||
}
|
||||
|
|
@ -183,4 +191,4 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue