in src/library/EndpointManagement/EndpointManagementClient.cs [324:401]
private async Task EnsureEndpointManagerRunningAsync(CancellationToken cancellationToken)
{
if (await this.IsCurrentEndpointManagerRunning(cancellationToken))
{
return;
}
var logFileDirectory = _fileSystem.Path.Combine(_fileSystem.Path.GetTempPath(), DirectoryName.Logs);
// Try to acquire the Mutex for launching the endpoint manager
using (var mutex = new Mutex(initiallyOwned: false, name: @"Global\BridgeEndpointManagerLaunch"))
{
try
{
var stopWatch = new Stopwatch();
stopWatch.Start();
while (stopWatch.Elapsed < _epmLaunchWaitTime)
{
_log.Verbose("Trying to acquire mutex...");
bool acquiredMutex = false;
try
{
// TimeSpan.Zero used to test the mutex's signal state and return immediately without blocking
acquiredMutex = mutex.WaitOne(TimeSpan.Zero);
}
catch (AbandonedMutexException ex)
{
// Another instance of bridge exited without releasing the mutex. We continue and take over.
_log.ExceptionAsWarning(ex);
break;
}
if (acquiredMutex)
{
_log.Verbose($"Acquired mutex. Proceeding to launch {nameof(EndpointManager)}.");
break;
}
_log.Verbose($"Another instance is open. Checking if {nameof(EndpointManager)} will come up...");
// Adding a timeout here. We have seen socket exceptions/connection refused in the past when we ping without any wait time.
await Task.Delay(TimeSpan.FromMilliseconds(200));
if (await this.IsCurrentEndpointManagerRunning(cancellationToken))
{
_log.Verbose($"Current endpoint manager is running. Returning.");
return;
}
}
// Determine the current user
(var exitCode, var currentUserName) = await _platform.DetermineCurrentUserWithRetriesAsync(cancellationToken);
var resultMessage = $"{nameof(_platform.DetermineCurrentUserWithRetriesAsync)} returned exit code {exitCode}";
if (exitCode != 0 || string.IsNullOrWhiteSpace(currentUserName))
{
_log.Error(resultMessage);
throw new UserVisibleException(_operationContext, Resources.FailedToDetermineCurrentUser);
}
_log.Verbose(resultMessage);
_endpointManagerLauncher.LaunchEndpointManager(currentUserName, _socketFilePath, logFileDirectory, cancellationToken);
await CheckEndpointManagerAliveAsync(cancellationToken);
}
catch (Exception ex) when (ex is IUserVisibleExceptionReporter)
{
// Always bubble up UserVisible exceptions
throw;
}
catch (Exception ex)
{
_log.Exception(ex);
throw new InvalidOperationException(string.Format(Resources.FailedToLaunchEndpointManagerFormat, EndpointManager.ProcessName));
}
finally
{
_log.Info("Releasing mutex if owned...");
try { mutex.ReleaseMutex(); } catch { }
}
}
}