Race condition with GetRandomUnusedPort()
Every so often our tests fail due to trying to start a listener for a port that is in use.
It's that time between the first listener stopping and the second one starting. Another thread might call GetRandomUnusedPort() in between and get the same port number.
This project hasn't been updated in a long time, so I'm not expecting a response here. However, in case anyone else discovers this I thought I'd share my workaround.
I'm using a variation on this answer from stack overflow. The gist of it is to just attempt to start a new HttpListener in a try/catch and use a different port each time until it works. This avoids a race condition since we're not relying on checking the ports currently in use, which can change at any time.
The example in the link goes through all ports in ascending order. In my own implementation, I choose a random port up to a specified maxAttempts.
private static bool TryBindListenerOnFreePort(int maxAttempts, out HttpListener httpListener, out int port)
{
const int minValue = 49152; // IANA suggested minimum value for dynamic or private ports.
const int maxValue = 65536; // IANA suggested maximum value for dynamic or private ports _plus one_. (Upper limit is _exclusive_.)
var attemptCount = 0;
var rand = new Random();
while (attemptCount < maxAttempts)
{
port = rand.Next(minValue, maxValue);
httpListener = new HttpListener();
httpListener.Prefixes.Add($"http://localhost:{port}/");
try
{
httpListener.Start();
return true;
}
catch
{
// nothing to do here -- the listener disposes itself when Start throws
}
attemptCount++;
}
port = 0;
httpListener = null;
return false;
}