private async Task EnsureEndpointManagerRunningAsync()

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 { }
                }
            }
        }