Quick fixes: Make `dotnet-getdocument` more reliable (#8716)

- use `WaitAny(...)` in inside man
- call `Process.WaitForExit()` twice
- `Flush()` all output `FileStream`s before disposal
- catch `UnauthorizedAccessException` when calling `File.Delete(...)` in case file's in use
- add `/nr:false` to `dotnet msbuild` command line
This commit is contained in:
Doug Bunting 2018-11-12 11:26:02 -08:00 committed by GitHub
parent 195a22d92c
commit 8308d94e39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 16 deletions

View File

@ -109,8 +109,8 @@ namespace Microsoft.Extensions.ApiDescription.Tool.Commands
return false;
}
var finished = Task.WhenAny(resultTask, Task.Delay(TimeSpan.FromMinutes(1)));
if (!ReferenceEquals(resultTask, finished))
var finishedIndex = Task.WaitAny(resultTask, Task.Delay(TimeSpan.FromMinutes(1)));
if (finishedIndex != 0)
{
Reporter.WriteWarning(Resources.FormatMethodTimedOut(methodName, serviceName, 1));
return false;
@ -121,6 +121,8 @@ namespace Microsoft.Extensions.ApiDescription.Tool.Commands
using (var outStream = File.Create(context.OutputPath))
{
stream.CopyTo(outStream);
outStream.Flush();
}
}

View File

@ -177,6 +177,8 @@ namespace Microsoft.Extensions.ApiDescription.Tasks
using (var outStream = File.Create(destinationPath))
{
await responseStream.CopyToAsync(outStream);
await outStream.FlushAsync();
}
}
}

View File

@ -186,8 +186,22 @@ namespace Microsoft.Extensions.ApiDescription.Tool.Commands
{
if (cleanupExecutable && !string.IsNullOrEmpty(executable))
{
File.Delete(executable);
File.Delete(executable + ".config");
// Ignore errors about in-use files. Should still be marked for delete after process cleanup.
try
{
File.Delete(executable);
}
catch (UnauthorizedAccessException)
{
}
try
{
File.Delete(executable + ".config");
}
catch (UnauthorizedAccessException)
{
}
}
}
}

View File

@ -1,6 +1,7 @@
// 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.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
@ -31,20 +32,32 @@ namespace Microsoft.Extensions.ApiDescription.Tool
startInfo.WorkingDirectory = workingDirectory;
}
var process = Process.Start(startInfo);
if (interceptOutput)
using (var process = Process.Start(startInfo))
{
string line;
while ((line = process.StandardOutput.ReadLine()) != null)
if (interceptOutput)
{
Reporter.WriteVerbose(line);
string line;
while ((line = process.StandardOutput.ReadLine()) != null)
{
Reporter.WriteVerbose(line);
}
}
// Follow precedent set in Razor integration tests and ensure process events and output are complete.
// https://github.com/aspnet/Razor/blob/d719920fdcc7d1db3a6f74cd5404d66fa098f057/test/Microsoft.NET.Sdk.Razor.Test/IntegrationTests/MSBuildProcessManager.cs#L91-L102
// Timeout is double how long the inside man waits for the IDocumentProcessor to wrap up.
if (!process.WaitForExit((int)(TimeSpan.FromMinutes(2).TotalMilliseconds)))
{
process.Kill();
// Should be unreachable in almost every case.
throw new TimeoutException($"Process {executable} timed out after 2 minutes.");
}
process.WaitForExit();
return process.ExitCode;
}
process.WaitForExit();
return process.ExitCode;
}
private static string ToArguments(IReadOnlyList<string> args)

View File

@ -89,6 +89,8 @@ namespace Microsoft.Extensions.ApiDescription.Tool
// NB: Copy always in case it changes
Reporter.WriteVerbose(Resources.FormatWritingFile(targetsPath));
input.CopyTo(output);
output.Flush();
}
}
@ -102,6 +104,7 @@ namespace Microsoft.Extensions.ApiDescription.Tool
"/target:WriteServiceProjectReferenceMetadata",
"/verbosity:quiet",
"/nologo",
"/nodeReuse:false",
$"/property:ServiceProjectReferenceMetadataPath={metadataPath}",
projectFile,
};
@ -134,8 +137,22 @@ namespace Microsoft.Extensions.ApiDescription.Tool
}
finally
{
File.Delete(metadataPath);
File.Delete(targetsPath);
// Ignore errors about in-use files. Should still be marked for delete after process cleanup.
try
{
File.Delete(metadataPath);
}
catch (UnauthorizedAccessException)
{
}
try
{
File.Delete(targetsPath);
}
catch (UnauthorizedAccessException)
{
}
}
var project = new Project