Skip to content

Do not respect NodeReuse for TaskHosts Fixes #3141#5144

Merged
Forgind merged 24 commits intodotnet:masterfrom
Forgind:node-reuse
Mar 18, 2020
Merged

Do not respect NodeReuse for TaskHosts Fixes #3141#5144
Forgind merged 24 commits intodotnet:masterfrom
Forgind:node-reuse

Conversation

@Forgind
Copy link
Copy Markdown
Contributor

@Forgind Forgind commented Feb 24, 2020

They can lock the node, causing errors.

Resolves #3141.

They can lock the node, causing errors.
Copy link
Copy Markdown
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a regression test? Maybe a test task that returns its PID, and validate that that PID is not alive at the end of the build?

ErrorUtilities.VerifyThrow(!_isTaskExecuting, "We should never have a task in the process of executing when we receive NodeBuildComplete.");

_shutdownReason = buildComplete.PrepareForReuse ? NodeEngineShutdownReason.BuildCompleteReuse : NodeEngineShutdownReason.BuildComplete;
_shutdownReason = NodeEngineShutdownReason.BuildComplete;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth a comment that there's no reuse scenario here because ...

@rainersigwald rainersigwald changed the title Do not respect NodeRuse for TaskHosts Fixes #3141 Do not respect NodeReuse for TaskHosts Fixes #3141 Feb 25, 2020
@rainersigwald rainersigwald added this to the MSBuild 16.6 Preview 2 milestone Mar 2, 2020
@cdmihai
Copy link
Copy Markdown
Contributor

cdmihai commented Mar 3, 2020

Wouldn't this slow down people whose builds call into out of proc task nodes many times? An escape hatch might be useful. I guess it depends which population is larger, the repos with frequently called out of proc tasks, or the repos that build their own tasks. Probably the later ...

@Forgind
Copy link
Copy Markdown
Contributor Author

Forgind commented Mar 3, 2020

I could add an escape hatch. I also considered trying to detect if the relevant task was a custom task or MSBuild task, but it got a little too complicated.

</Target>
</Project>";
TransientTestFile project = env.CreateFile("testProject.csproj", pidTaskProject);
MockLogger logger = new MockLogger();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
MockLogger logger = new MockLogger();
MockLogger logger = new MockLogger(_output);

public readonly bool UseSymlinkTimeInsteadOfTargetTime = Environment.GetEnvironmentVariable("MSBUILDUSESYMLINKTIMESTAMP") == "1";

/// <summary>
/// Allow node reuse on TaskHost nodes. This breaks if there are custom tasks.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Allow node reuse on TaskHost nodes. This breaks if there are custom tasks.
/// Allow node reuse of TaskHost nodes. This results in task assemblies locked past the build lifetime, but may improve performance.

using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Build.UnitTests;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move unrelated edit to a new PR or just revert.


[Fact]
[SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp, "https://github.com/microsoft/msbuild/issues/5158")]
public void TaskNodesDieAfterBuild()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this test in this class? It's not about warnings-as-messages. Can you find a better home, like maybe a new TaskHostFactory_Tests?

Comment on lines +42 to +44
int start = logger.FullLog.IndexOf(introToPID) + introToPID.Length;
int length = logger.FullLog.IndexOf(afterPID) - start;
string pid = logger.FullLog.Substring(start, length);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of grepping through the logging, can you change the test to return the PID of its process as a property, capture the property into a named property when you call it, and read the property out of the built project instance? That's a much cleaner way to do things (and a good exercise for you in using our API).

Copy link
Copy Markdown
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, misclick on previous review.

@@ -0,0 +1,38 @@
using System;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copyright header please

public class ProcessIdTask : Task
{
[Output]
public Int32 pid { get; set; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public Int32 pid { get; set; }
public int Pid { get; set; }

style nits: use the C# type where possible, and properties should start with a capital letter.

public sealed class TaskHostFactory_Tests
{
[Fact]
[SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp, "https://github.com/microsoft/msbuild/issues/5158")]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work on Mono?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Mono support out-of-proc task hosts? I was going to find out with the automated tests.

Forgind added 3 commits March 5, 2020 15:34
This will indicate if we're using a TaskHostNode as expected in the new test.
Copy link
Copy Markdown
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after test tweaks

Should.Throw<ArgumentException>(() => Process.GetProcessById(pid));
try {
Process taskHostNode = Process.GetProcessById(pid);
taskHostNode.WaitForExit(2000);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert that this reported that the process ended (and didn't time out).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's caught by the Should.Throw immediately afterwards. If it times out, Process.GetProcessById won't throw, and the test will fail.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily though, given PID reuse.

Comment on lines +44 to +47
catch (Exception e)
{
e.ShouldBeOfType<ArgumentException>();
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this catch?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want taskHostNode to die. If it dies before this try statement, Process.GetProcessById will throw an ArgumentException, so this test succeeded if either the Should.Throw statement succeeds or the node dies fast, and Process.GetProcessById throws an ArgumentException.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment with that reasoning, catch only the exact exception, minimize the scope of the catch, and can you assert details of it?

@Forgind
Copy link
Copy Markdown
Contributor Author

Forgind commented Mar 18, 2020

Checked with @rainersigwald, and this does not work on mono, so disabling the test seems reasonable.

@Forgind Forgind merged commit 3453bee into dotnet:master Mar 18, 2020
@Forgind Forgind deleted the node-reuse branch March 18, 2020 21:53
rainersigwald added a commit to rainersigwald/visualstudio-docs that referenced this pull request Apr 13, 2023
In some offline discussion, @jaredpar pointed out that the TaskHostFactory docs didn't specify that the TaskHost node wouldn't live on past the build. It has since 16.6 (dotnet/msbuild#5144), so document that.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Node reuse locks task assembly file

3 participants