Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/installer/tests/TestUtils/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -120,7 +121,7 @@ private static bool ShouldUseCmd(string executable)
}
else
{
// Search the path to see if we can find it
// Search the path to see if we can find it
foreach (var path in System.Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator))
{
var candidate = Path.Combine(path, executable + ".exe");
Expand Down Expand Up @@ -196,7 +197,22 @@ public Command Start()

ReportExecBegin();

Process.Start();
// Retry if we hit ETXTBSY due to Linux race
// https://github.com/dotnet/runtime/issues/58964
for (int i = 0; ; i++)
{
try
{
Process.Start();
break;
}
catch (Win32Exception e) when (i < 3 && e.Message.Contains("Text file busy"))
{
// 10 ms is short, but the race we're trying to avoid is in-between
// "fork" and "exec", so it should be fast
Copy link
Member

Choose a reason for hiding this comment

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

to balance latency and likelihood of waiting long enough, perhaps we should scale the backoff a little, like this could be Sleep(i * 10) ?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's probably worth seeing if this solves the issue, but there's no reason we can't come back to it later.

Thread.Sleep(10);
Copy link
Member

Choose a reason for hiding this comment

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

Ideally this should print out some diagnostics - so that we know it happened. Not sure if Console.WriteLine is the correct solution here - but it might be.

Copy link
Member Author

Choose a reason for hiding this comment

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

Console.WriteLine is captured by XUnit so I don't think that would work.

Why would this code in particular be worthy of a diagnostic? I've found a few other places where we appear to retry without warning, e.g. in TestFileBackup:

                // Directory.Delete sometimes fails with error that the directory is not empty.
                // This is a known problem where the actual Delete call is not 100% synchronous
                // the OS reports a success but the file/folder is not fully removed yet.
                // So implement a simple retry with a short timeout.
                IOException exception = null;
                for (int retryCount = 5; retryCount > 0; retryCount--)
                {
                    try
                    {
                        Directory.Delete(_backupPath, recursive: true);
                        if (!Directory.Exists(_backupPath))
                        {
                            return;
                        }
                    }
                    catch (IOException ex)
                    {
                        exception = ex;
                    }

                    System.Threading.Thread.Sleep(200);
                }

Copy link
Member

Choose a reason for hiding this comment

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

Since this has been giving us trouble, having enough info to diagnose potential issues sounds like a good idea.
I know that we don't have existing diagnostics, but ideally that should not block us from adding them 😉.

That said - I don't know how the diagnostics should look. Is there some existing mechanism for tests to output additional info to be used in case of failure (but honestly it would be great to get this even on passes if it's not too verbose).

Copy link
Member Author

Choose a reason for hiding this comment

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

Unfortunately I don't know of a good logging mechanism at the moment. This code could be executed across many threads, so there would likely need to be some coordination for anything useful to come out.

}
}

if (Process.StartInfo.RedirectStandardOutput)
{
Expand Down