private static AsyncPolicy CreateRetryPolicy(IConfiguration configuration, Extensions.Logging.ILogger logger) { var retryMigrations = false; bool.TryParse(configuration["RetryMigrations"], out retryMigrations); // Only use a retry policy if configured to do so. // When running in an orchestrator/K8s, it will take care of restarting failed services. if (retryMigrations) { return(Policy.Handle <Exception>(). WaitAndRetryForeverAsync( sleepDurationProvider: retry => TimeSpan.FromSeconds(5), onRetry: (exception, retry, timeSpan) => { logger.LogWarning( exception, "Exception {ExceptionType} with message {Message} detected during database migration (retry attempt {retry})", exception.GetType().Name, exception.Message, retry); } )); } return(Policy.NoOpAsync()); }
public static async Task <int> MainAsync(IConfiguration configuration) { // Bring up the logger before anything else so we can log errors ASAP ILogger logger = SetupLogger(configuration); logger.LogInformation("Starting module management agent."); VersionInfo versionInfo = VersionInfo.Get(VersionInfoFileName); if (versionInfo != VersionInfo.Empty) { logger.LogInformation($"Version - {versionInfo.ToString(true)}"); } LogLogo(logger); string mode; string configSourceConfig; string backupConfigFilePath; int maxRestartCount; TimeSpan intensiveCareTime; int coolOffTimeUnitInSeconds; bool usePersistentStorage; string storagePath; string edgeDeviceHostName; string dockerLoggingDriver; Dictionary <string, string> dockerLoggingOptions; IEnumerable <AuthConfig> dockerAuthConfig; int configRefreshFrequencySecs; try { mode = configuration.GetValue(Constants.ModeKey, "docker"); configSourceConfig = configuration.GetValue <string>("ConfigSource"); backupConfigFilePath = configuration.GetValue <string>("BackupConfigFilePath"); maxRestartCount = configuration.GetValue <int>("MaxRestartCount"); intensiveCareTime = TimeSpan.FromMinutes(configuration.GetValue <int>("IntensiveCareTimeInMinutes")); coolOffTimeUnitInSeconds = configuration.GetValue("CoolOffTimeUnitInSeconds", 10); usePersistentStorage = configuration.GetValue("UsePersistentStorage", true); storagePath = GetStoragePath(configuration); edgeDeviceHostName = configuration.GetValue <string>(Constants.EdgeDeviceHostNameKey); dockerLoggingDriver = configuration.GetValue <string>("DockerLoggingDriver"); dockerLoggingOptions = configuration.GetSection("DockerLoggingOptions").Get <Dictionary <string, string> >() ?? new Dictionary <string, string>(); dockerAuthConfig = configuration.GetSection("DockerRegistryAuth").Get <List <AuthConfig> >() ?? new List <AuthConfig>(); configRefreshFrequencySecs = configuration.GetValue("ConfigRefreshFrequencySecs", 3600); } catch (Exception ex) { logger.LogCritical(AgentEventIds.Agent, ex, "Fatal error reading the Agent's configuration."); return(1); } IContainer container; try { var builder = new ContainerBuilder(); builder.RegisterModule(new LoggingModule(dockerLoggingDriver, dockerLoggingOptions)); Option <string> productInfo = versionInfo != VersionInfo.Empty ? Option.Some(versionInfo.ToString()) : Option.None <string>(); Option <UpstreamProtocol> upstreamProtocol = configuration.GetValue <string>(Constants.UpstreamProtocolKey).ToUpstreamProtocol(); switch (mode.ToLowerInvariant()) { case Constants.DockerMode: var dockerUri = new Uri(configuration.GetValue <string>("DockerUri")); string deviceConnectionString = configuration.GetValue <string>("DeviceConnectionString"); builder.RegisterModule(new AgentModule(maxRestartCount, intensiveCareTime, coolOffTimeUnitInSeconds, usePersistentStorage, storagePath)); builder.RegisterModule(new DockerModule(deviceConnectionString, edgeDeviceHostName, dockerUri, dockerAuthConfig, upstreamProtocol, productInfo)); break; case Constants.IotedgedMode: string managementUri = configuration.GetValue <string>(Constants.EdgeletManagementUriVariableName); string workloadUri = configuration.GetValue <string>(Constants.EdgeletWorkloadUriVariableName); string iothubHostname = configuration.GetValue <string>(Constants.IotHubHostnameVariableName); string deviceId = configuration.GetValue <string>(Constants.DeviceIdVariableName); string moduleId = configuration.GetValue(Constants.ModuleIdVariableName, Constants.EdgeAgentModuleIdentityName); string moduleGenerationId = configuration.GetValue <string>(Constants.EdgeletModuleGenerationIdVariableName); builder.RegisterModule(new AgentModule(maxRestartCount, intensiveCareTime, coolOffTimeUnitInSeconds, usePersistentStorage, storagePath, Option.Some(new Uri(workloadUri)), moduleId, Option.Some(moduleGenerationId))); builder.RegisterModule(new EdgeletModule(iothubHostname, edgeDeviceHostName, deviceId, new Uri(managementUri), new Uri(workloadUri), dockerAuthConfig, upstreamProtocol, productInfo)); break; default: throw new InvalidOperationException($"Mode '{mode}' not supported."); } switch (configSourceConfig.ToLowerInvariant()) { case "twin": builder.RegisterModule(new TwinConfigSourceModule(backupConfigFilePath, configuration, versionInfo, TimeSpan.FromSeconds(configRefreshFrequencySecs))); break; case "local": builder.RegisterModule(new FileConfigSourceModule("config.json", configuration)); break; default: throw new InvalidOperationException($"ConfigSource '{configSourceConfig}' not supported."); } container = builder.Build(); } catch (Exception ex) { logger.LogCritical(AgentEventIds.Agent, ex, "Fatal error building application."); return(1); } (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(ShutdownWaitPeriod, logger); int returnCode; using (IConfigSource unused = await container.Resolve <Task <IConfigSource> >()) { Option <Agent> agentOption = Option.None <Agent>(); try { Agent agent = await container.Resolve <Task <Agent> >(); agentOption = Option.Some(agent); while (!cts.Token.IsCancellationRequested) { try { await agent.ReconcileAsync(cts.Token); } catch (Exception ex) when(!ex.IsFatal()) { logger.LogWarning(AgentEventIds.Agent, ex, "Agent reconcile concluded with errors."); } await Task.Delay(TimeSpan.FromSeconds(5), cts.Token); } logger.LogInformation("Closing module management agent."); returnCode = 0; } catch (OperationCanceledException) { logger.LogInformation("Main thread terminated"); returnCode = 0; } catch (Exception ex) { logger.LogCritical(AgentEventIds.Agent, ex, "Fatal error starting Agent."); returnCode = 1; } // Attempt to report shutdown of Agent await Cleanup(agentOption, logger); completed.Set(); } handler.ForEach(h => GC.KeepAlive(h)); return(returnCode); }
public void LogWarning(string message) => _logger.LogWarning(message);