private IEnumerable <LocalProcess> GetManagedProcesses(
            AgentConfiguration agentConfiguration)
        {
            if (agentConfiguration.Ports == null || agentConfiguration.Ports.Count == 0)
            {
                // No ports specified, use ephemeral ports
                agentConfiguration.Ports =
                    new List <int>(Enumerable.Repeat(-1, agentConfiguration.ProcessCount));
            }

            if (agentConfiguration.Ports.Count != agentConfiguration.ProcessCount)
            {
                throw new ArgumentException(
                          "Number of ports must correspond to process count or be zero for ephemeral port usage");
            }

            for (int i = 0; i < agentConfiguration.ProcessCount; i++)
            {
                string hostName = agentConfiguration.HostName;
                int    port     = agentConfiguration.Ports[i];

                ChannelCredentials credentials =
                    GrpcUtils.CreateChannelCredentials(agentConfiguration.UseTls,
                                                       agentConfiguration.ClientCertificate);

                var managedProcess = new LocalProcess(agentConfiguration.AgentType,
                                                      agentConfiguration.ExecutablePath, agentConfiguration.CommandLineArguments,
                                                      hostName, port, credentials)
                {
                    EnvironmentVariables   = agentConfiguration.EnvironmentVariables,
                    ClusterShutdownAction  = agentConfiguration.ClusterShutdownAction,
                    RecyclingIntervalHours = GetRandomizedRecyclingInterval(agentConfiguration),
                    StartupWaitSeconds     = agentConfiguration.StartupWaitSeconds
                };

                if (agentConfiguration.ServiceNames != null)
                {
                    foreach (string serviceName in agentConfiguration.ServiceNames)
                    {
                        managedProcess.ServiceNames.Add(serviceName);
                    }
                }

                _logger.LogInformation(
                    "Agent has been configured with recycling interval {recyclingHours:F3}h. Process details: {process}",
                    managedProcess.RecyclingIntervalHours, managedProcess);

                yield return(managedProcess);
            }
        }
        private Channel GetChannel(ServiceLocation serviceLocation)
        {
            if (!_channelCache.TryGetValue(serviceLocation, out Channel channel))
            {
                ChannelCredentials channelCredentials = GrpcUtils.CreateChannelCredentials(
                    serviceLocation.UseTls, _clientCertificate);

                channel = GrpcUtils.CreateChannel(serviceLocation.HostName, serviceLocation.Port,
                                                  channelCredentials);

                if (!_channelCache.TryAdd(serviceLocation, channel))
                {
                    // It's been added in the meanwhile by another request on another thread
                    channel = _channelCache[serviceLocation];
                }
            }

            return(channel);
        }