static async Task MainAsync()

in edge-hub/core/src/Microsoft.Azure.Devices.Edge.Hub.Service/Program.cs [86:206]


        static async Task<int> MainAsync(IConfigurationRoot configuration, ILogger logger)
        {
            try
            {
                EdgeHubCertificates certificates = await EdgeHubCertificates.LoadAsync(configuration, logger);
                bool clientCertAuthEnabled = configuration.GetValue(Constants.ConfigKey.EdgeHubClientCertAuthEnabled, false);

                string sslProtocolsConfig = configuration.GetValue(Constants.ConfigKey.SslProtocols, string.Empty);
                SslProtocols sslProtocols = SslProtocolsHelper.Parse(sslProtocolsConfig, DefaultSslProtocols, logger);
                logger.LogInformation($"Enabling SSL protocols: {sslProtocols.Print()}");

                IDependencyManager dependencyManager = new DependencyManager(configuration, certificates.ServerCertificate, certificates.TrustBundle, certificates.ManifestTrustBundle, sslProtocols);
                Hosting hosting = Hosting.Initialize(configuration, certificates.ServerCertificate, dependencyManager, clientCertAuthEnabled, sslProtocols);
                IContainer container = hosting.Container;

                logger.LogInformation("Initializing Edge Hub");
                LogLogo(logger);
                LogVersionInfo(logger);
                logger.LogInformation($"OptimizeForPerformance={configuration.GetValue("OptimizeForPerformance", true)}");
                logger.LogInformation($"MessageAckTimeoutSecs={configuration.GetValue("MessageAckTimeoutSecs", 30)}");
                logger.LogInformation("Loaded server certificate with expiration date of {0}", certificates.ServerCertificate.NotAfter.ToString("o"));

                var metricsProvider = container.Resolve<IMetricsProvider>();
                Metrics.InitWithAspNet(metricsProvider, logger); // Note this requires App.UseMetricServer() to be called in Startup.cs

                // EdgeHub and CloudConnectionProvider have a circular dependency. So need to Bind the EdgeHub to the CloudConnectionProvider.
                IEdgeHub edgeHub = await container.Resolve<Task<IEdgeHub>>();
                ICloudConnectionProvider cloudConnectionProvider = await container.Resolve<Task<ICloudConnectionProvider>>();
                cloudConnectionProvider.BindEdgeHub(edgeHub);

                // EdgeHub cloud proxy and DeviceConnectivityManager have a circular dependency,
                // so the cloud proxy has to be set on the DeviceConnectivityManager after both have been initialized.
                var deviceConnectivityManager = container.Resolve<IDeviceConnectivityManager>();
                IConnectionManager connectionManager = await container.Resolve<Task<IConnectionManager>>();
                (deviceConnectivityManager as DeviceConnectivityManager)?.SetConnectionManager(connectionManager);

                // Register EdgeHub credentials
                var edgeHubCredentials = container.ResolveNamed<IClientCredentials>("EdgeHubCredentials");
                ICredentialsCache credentialsCache = await container.Resolve<Task<ICredentialsCache>>();
                await credentialsCache.Add(edgeHubCredentials);

                // Register EdgeHub indentity in device scopes cache.
                // When we connect upstream, we verify that identity is in scope.
                // On a fresh start, we may not yet received the scopes from the upstream, so we need
                // to force add edgeHub in the cache so it is able to connect upstream.
                // Once we get the scopes from the upstream, this record is replaced.
                ServiceIdentity edgeHubIdentity = container.ResolveNamed<ServiceIdentity>("EdgeHubIdentity");
                IServiceIdentityHierarchy identityScopes = container.Resolve<IServiceIdentityHierarchy>();
                await identityScopes.AddOrUpdate(edgeHubIdentity);

                // Initializing configuration
                logger.LogInformation("Initializing configuration");
                IConfigSource configSource = await container.Resolve<Task<IConfigSource>>();
                ConfigUpdater configUpdater = await container.Resolve<Task<ConfigUpdater>>();
                ExperimentalFeatures experimentalFeatures = CreateExperimentalFeatures(configuration);
                var configUpdaterStartupFailed = new TaskCompletionSource<bool>();
                var configDownloadTask = configUpdater.Init(configSource);

                _ = configDownloadTask.ContinueWith(
                                                _ => configUpdaterStartupFailed.SetResult(false),
                                                TaskContinuationOptions.OnlyOnFaulted);

                if (!Enum.TryParse(configuration.GetValue("AuthenticationMode", string.Empty), true, out AuthenticationMode authenticationMode)
                    || authenticationMode != AuthenticationMode.Cloud)
                {
                    ConnectionReauthenticator connectionReauthenticator = await container.Resolve<Task<ConnectionReauthenticator>>();
                    connectionReauthenticator.Init();
                }

                TimeSpan shutdownWaitPeriod = TimeSpan.FromSeconds(configuration.GetValue("ShutdownWaitPeriod", DefaultShutdownWaitPeriod));
                (CancellationTokenSource cts, ManualResetEventSlim completed, Option<object> handler) = ShutdownHandler.Init(shutdownWaitPeriod, logger);
                var protocolTimeout = configuration.GetValue("protocolTimeoutInSecs", 180);
                TimeSpan protocolTimeoutinSecs = TimeSpan.FromSeconds(protocolTimeout);

                int renewAfter = configuration.GetValue("ServerCertificateRenewAfterInMs", int.MaxValue);
                TimeSpan maxRenewAfter = TimeSpan.FromMilliseconds(renewAfter);

                int? maxCheckCertExpiryAfterMs = configuration.GetValue<int?>("MaxCheckCertExpiryInMs");
                Option<TimeSpan> maxCheckCertExpiryAfter = maxCheckCertExpiryAfterMs.HasValue ? Option.Some(TimeSpan.FromMilliseconds(maxCheckCertExpiryAfterMs.Value)) : Option.None<TimeSpan>();

                using (IProtocolHead mqttBrokerProtocolHead = GetMqttBrokerProtocolHead(container))
                using (IProtocolHead edgeHubProtocolHead = await GetEdgeHubProtocolHeadAsync(logger, configuration, container, hosting))
                using (var renewal = new CertificateRenewal(certificates, logger, maxRenewAfter, maxCheckCertExpiryAfter))
                {
                    try
                    {
                        await Task.WhenAll(mqttBrokerProtocolHead.StartAsync(), configDownloadTask);
                        await edgeHubProtocolHead.StartAsync();
                        await Task.WhenAny(cts.Token.WhenCanceled(), renewal.Token.WhenCanceled(), configUpdaterStartupFailed.Task);
                    }
                    catch (Exception ex)
                    {
                        logger.LogError($"Error starting protocol heads: {ex.Message}");
                    }

                    logger.LogInformation("Stopping the protocol heads...");
                    try
                    {
                        await TaskEx.TimeoutAfter(Task.WhenAll(mqttBrokerProtocolHead.CloseAsync(CancellationToken.None), edgeHubProtocolHead.CloseAsync(CancellationToken.None)), protocolTimeoutinSecs);
                        logger.LogInformation("Protocol heads stopped.");
                    }
                    catch (Exception ex)
                    {
                        logger.LogError($"Error stopping protocol heads: {ex.Message}");
                    }

                    await CloseDbStoreProviderAsync(container);
                }

                completed.Set();
                handler.ForEach(h => GC.KeepAlive(h));
                logger.LogInformation("Shutdown complete.");
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Stopping with exception");
                return 1;
            }

            return 0;
        }