public static void Main(string[] args) => Run(new ProgramOptions { Hosting = { HttpPort = 5006 }, Logging = { WriteTextToConsole = false, WriteJsonToConsole = false }, Runtime = { CommandLineArgs = args }, MiddlewareHooks = { ConfigureDistributedLock = configuration => DistributedLockOptions.LoadFromConfiguration(configuration) } });
public static async Task Main(string[] args) { var ct = CancellationTokenSource.Token; ct.Register(() => Closing.Set()); Console.CancelKeyPress += (sender, eventArgs) => CancellationTokenSource.Cancel(); AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => Log.Debug( eventArgs.Exception, "FirstChanceException event raised in {AppDomain}.", AppDomain.CurrentDomain.FriendlyName); AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) => Log.Fatal((Exception)eventArgs.ExceptionObject, "Encountered a fatal exception, exiting program."); var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) .AddJsonFile($"appsettings.{Environment.MachineName.ToLowerInvariant()}.json", optional: true, reloadOnChange: false) .AddEnvironmentVariables() .AddCommandLine(args ?? new string[0]) .Build(); var container = ConfigureServices(configuration); Log.Information("Starting BuildingRegistry.Projections.Syndication"); try { await DistributedLock <Program> .RunAsync( async() => { try { await MigrationsHelper.RunAsync( configuration.GetConnectionString("SyndicationProjectionsAdmin"), container.GetService <ILoggerFactory>(), ct); await Task.WhenAll(StartRunners(configuration, container, ct)); Log.Information("Running... Press CTRL + C to exit."); Closing.WaitOne(); } catch (Exception e) { Log.Fatal(e, "Encountered a fatal exception, exiting program."); throw; } }, DistributedLockOptions.LoadFromConfiguration(configuration) ?? DistributedLockOptions.Defaults, container.GetService <ILogger <Program> >()); } catch (Exception e) { Log.Fatal(e, "Encountered a fatal exception, exiting program."); Log.CloseAndFlush(); // Allow some time for flushing before shutdown. Thread.Sleep(1000); throw; } Log.Information("Stopping..."); Closing.Close(); }
public static async Task Main(string[] args) { Console.WriteLine("Starting RoadRegistry.Product.ProjectionHost"); AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => Log.Debug(eventArgs.Exception, "FirstChanceException event raised in {AppDomain}.", AppDomain.CurrentDomain.FriendlyName); AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) => Log.Fatal((Exception)eventArgs.ExceptionObject, "Encountered a fatal exception, exiting program."); var host = new HostBuilder() .ConfigureHostConfiguration(builder => { builder .AddEnvironmentVariables("DOTNET_") .AddEnvironmentVariables("ASPNETCORE_"); }) .ConfigureAppConfiguration((hostContext, builder) => { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); if (hostContext.HostingEnvironment.IsProduction()) { builder .SetBasePath(Directory.GetCurrentDirectory()); } builder .AddJsonFile("appsettings.json", true, false) .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName.ToLowerInvariant()}.json", true, false) .AddJsonFile($"appsettings.{Environment.MachineName.ToLowerInvariant()}.json", true, false) .AddEnvironmentVariables() .AddCommandLine(args); }) .ConfigureLogging((hostContext, builder) => { Serilog.Debugging.SelfLog.Enable(Console.WriteLine); var loggerConfiguration = new LoggerConfiguration() .ReadFrom.Configuration(hostContext.Configuration) .Enrich.FromLogContext() .Enrich.WithMachineName() .Enrich.WithThreadId() .Enrich.WithEnvironmentUserName(); Log.Logger = loggerConfiguration.CreateLogger(); builder.AddSerilog(Log.Logger); }) .ConfigureServices((hostContext, builder) => { var blobOptions = new BlobClientOptions(); hostContext.Configuration.Bind(blobOptions); switch (blobOptions.BlobClientType) { case nameof(S3BlobClient): var s3Options = new S3BlobClientOptions(); hostContext.Configuration.GetSection(nameof(S3BlobClientOptions)).Bind(s3Options); // Use MINIO if (hostContext.Configuration.GetValue <string>("MINIO_SERVER") != null) { if (hostContext.Configuration.GetValue <string>("MINIO_ACCESS_KEY") == null) { throw new Exception("The MINIO_ACCESS_KEY configuration variable was not set."); } if (hostContext.Configuration.GetValue <string>("MINIO_SECRET_KEY") == null) { throw new Exception("The MINIO_SECRET_KEY configuration variable was not set."); } builder.AddSingleton(new AmazonS3Client( new BasicAWSCredentials( hostContext.Configuration.GetValue <string>("MINIO_ACCESS_KEY"), hostContext.Configuration.GetValue <string>("MINIO_SECRET_KEY")), new AmazonS3Config { RegionEndpoint = RegionEndpoint.USEast1, // minio's default region ServiceURL = hostContext.Configuration.GetValue <string>("MINIO_SERVER"), ForcePathStyle = true } ) ); } else // Use AWS { if (hostContext.Configuration.GetValue <string>("AWS_ACCESS_KEY_ID") == null) { throw new Exception("The AWS_ACCESS_KEY_ID configuration variable was not set."); } if (hostContext.Configuration.GetValue <string>("AWS_SECRET_ACCESS_KEY") == null) { throw new Exception("The AWS_SECRET_ACCESS_KEY configuration variable was not set."); } builder.AddSingleton(new AmazonS3Client( new BasicAWSCredentials( hostContext.Configuration.GetValue <string>("AWS_ACCESS_KEY_ID"), hostContext.Configuration.GetValue <string>("AWS_SECRET_ACCESS_KEY")) ) ); } builder.AddSingleton <IBlobClient>(sp => new S3BlobClient( sp.GetService <AmazonS3Client>(), s3Options.Buckets[WellknownBuckets.UploadsBucket] ) ); break; case nameof(FileBlobClient): var fileOptions = new FileBlobClientOptions(); hostContext.Configuration.GetSection(nameof(FileBlobClientOptions)).Bind(fileOptions); builder.AddSingleton <IBlobClient>(sp => new FileBlobClient( new DirectoryInfo(fileOptions.Directory) ) ); break; default: throw new Exception(blobOptions.BlobClientType + " is not a supported blob client type."); } builder .AddSingleton <IClock>(SystemClock.Instance) .AddSingleton <Scheduler>() .AddHostedService <EventProcessor>() .AddSingleton(new RecyclableMemoryStreamManager()) .AddSingleton(new EnvelopeFactory( EventProcessor.EventMapping, new EventDeserializer((eventData, eventType) => JsonConvert.DeserializeObject(eventData, eventType, EventProcessor.SerializerSettings))) ) .AddSingleton <Func <ProductContext> >( () => new ProductContext( new DbContextOptionsBuilder <ProductContext>() .UseSqlServer( hostContext.Configuration.GetConnectionString(WellknownConnectionNames.ProductProjections), options => options.EnableRetryOnFailure() ).Options) ) .AddSingleton(sp => new ConnectedProjection <ProductContext>[] { new OrganizationRecordProjection(sp.GetRequiredService <RecyclableMemoryStreamManager>(), WindowsAnsiEncoding), new GradeSeparatedJunctionRecordProjection(sp.GetRequiredService <RecyclableMemoryStreamManager>(), WindowsAnsiEncoding), new RoadNetworkInfoProjection(), new RoadNodeRecordProjection(sp.GetRequiredService <RecyclableMemoryStreamManager>(), WindowsAnsiEncoding), new RoadSegmentEuropeanRoadAttributeRecordProjection(sp.GetRequiredService <RecyclableMemoryStreamManager>(), WindowsAnsiEncoding), new RoadSegmentLaneAttributeRecordProjection(sp.GetRequiredService <RecyclableMemoryStreamManager>(), WindowsAnsiEncoding), new RoadSegmentNationalRoadAttributeRecordProjection(sp.GetRequiredService <RecyclableMemoryStreamManager>(), WindowsAnsiEncoding), new RoadSegmentNumberedRoadAttributeRecordProjection(sp.GetRequiredService <RecyclableMemoryStreamManager>(), WindowsAnsiEncoding), new RoadSegmentRecordProjection(sp.GetRequiredService <RecyclableMemoryStreamManager>(), WindowsAnsiEncoding), new RoadSegmentSurfaceAttributeRecordProjection(sp.GetRequiredService <RecyclableMemoryStreamManager>(), WindowsAnsiEncoding), new RoadSegmentWidthAttributeRecordProjection(sp.GetRequiredService <RecyclableMemoryStreamManager>(), WindowsAnsiEncoding) }) .AddSingleton(sp => Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector.Resolve .WhenEqualToHandlerMessageType( sp.GetRequiredService <ConnectedProjection <ProductContext>[]>() .SelectMany(projection => projection.Handlers) .ToArray() ) ) .AddSingleton(sp => AcceptStreamMessage.WhenEqualToMessageType(sp.GetRequiredService <ConnectedProjection <ProductContext>[]>(), EventProcessor.EventMapping)) .AddSingleton <IStreamStore>(sp => new MsSqlStreamStore( new MsSqlStreamStoreSettings( sp .GetService <IConfiguration>() .GetConnectionString(WellknownConnectionNames.Events) ) { Schema = WellknownSchemas.EventSchema })) .AddSingleton <IRunnerDbContextMigratorFactory>(new ProductContextMigrationFactory()); }) .Build(); var migratorFactory = host.Services.GetRequiredService <IRunnerDbContextMigratorFactory>(); var configuration = host.Services.GetRequiredService <IConfiguration>(); var streamStore = host.Services.GetRequiredService <IStreamStore>(); var loggerFactory = host.Services.GetRequiredService <ILoggerFactory>(); var logger = host.Services.GetRequiredService <ILogger <Program> >(); var blobClientOptions = new BlobClientOptions(); configuration.Bind(blobClientOptions); try { await WaitFor.SeqToBecomeAvailable(configuration).ConfigureAwait(false); logger.LogSqlServerConnectionString(configuration, WellknownConnectionNames.Events); logger.LogSqlServerConnectionString(configuration, WellknownConnectionNames.ProductProjections); logger.LogSqlServerConnectionString(configuration, WellknownConnectionNames.ProductProjectionsAdmin); logger.LogBlobClientCredentials(blobClientOptions); await DistributedLock <Program> .RunAsync(async() => { await WaitFor.SqlStreamStoreToBecomeAvailable(streamStore, logger).ConfigureAwait(false); await migratorFactory.CreateMigrator(configuration, loggerFactory) .MigrateAsync(CancellationToken.None).ConfigureAwait(false); await host.RunAsync().ConfigureAwait(false); }, DistributedLockOptions.LoadFromConfiguration(configuration), logger) .ConfigureAwait(false); } catch (Exception e) { logger.LogCritical(e, "Encountered a fatal exception, exiting program."); } finally { Log.CloseAndFlush(); } }
private static async Task Main(string[] args) { AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => Log.Debug(eventArgs.Exception, "FirstChanceException event raised in {AppDomain}.", AppDomain.CurrentDomain.FriendlyName); AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) => Log.Fatal((Exception)eventArgs.ExceptionObject, "Encountered a fatal exception, exiting program."); var host = new HostBuilder() .ConfigureHostConfiguration(builder => { builder .AddEnvironmentVariables("DOTNET_") .AddEnvironmentVariables("ASPNETCORE_"); }) .ConfigureAppConfiguration((hostContext, builder) => { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); if (hostContext.HostingEnvironment.IsProduction()) { builder .SetBasePath(Directory.GetCurrentDirectory()); } builder .AddJsonFile("appsettings.json", true, false) .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName.ToLowerInvariant()}.json", true, false) .AddJsonFile($"appsettings.{Environment.MachineName.ToLowerInvariant()}.json", true, false) .AddEnvironmentVariables() .AddCommandLine(args) .Build(); }) .ConfigureLogging((hostContext, builder) => { Serilog.Debugging.SelfLog.Enable(Console.WriteLine); var loggerConfiguration = new LoggerConfiguration() .ReadFrom.Configuration(hostContext.Configuration) .Enrich.FromLogContext() .Enrich.WithMachineName() .Enrich.WithThreadId() .Enrich.WithEnvironmentUserName(); Log.Logger = loggerConfiguration.CreateLogger(); builder.AddSerilog(Log.Logger); }) .ConfigureServices((hostContext, builder) => { var blobOptions = new BlobClientOptions(); hostContext.Configuration.Bind(blobOptions); switch (blobOptions.BlobClientType) { case nameof(S3BlobClient): var s3Options = new S3BlobClientOptions(); hostContext.Configuration.GetSection(nameof(S3BlobClientOptions)).Bind(s3Options); // Use MINIO if (hostContext.Configuration.GetValue <string>("MINIO_SERVER") != null) { if (hostContext.Configuration.GetValue <string>("MINIO_ACCESS_KEY") == null) { throw new Exception("The MINIO_ACCESS_KEY configuration variable was not set."); } if (hostContext.Configuration.GetValue <string>("MINIO_SECRET_KEY") == null) { throw new Exception("The MINIO_SECRET_KEY configuration variable was not set."); } builder.AddSingleton(new AmazonS3Client( new BasicAWSCredentials( hostContext.Configuration.GetValue <string>("MINIO_ACCESS_KEY"), hostContext.Configuration.GetValue <string>("MINIO_SECRET_KEY")), new AmazonS3Config { RegionEndpoint = RegionEndpoint.USEast1, // minio's default region ServiceURL = hostContext.Configuration.GetValue <string>("MINIO_SERVER"), ForcePathStyle = true } ) ); } else // Use AWS { if (hostContext.Configuration.GetValue <string>("AWS_ACCESS_KEY_ID") == null) { throw new Exception("The AWS_ACCESS_KEY_ID configuration variable was not set."); } if (hostContext.Configuration.GetValue <string>("AWS_SECRET_ACCESS_KEY") == null) { throw new Exception("The AWS_SECRET_ACCESS_KEY configuration variable was not set."); } builder.AddSingleton(new AmazonS3Client( new BasicAWSCredentials( hostContext.Configuration.GetValue <string>("AWS_ACCESS_KEY_ID"), hostContext.Configuration.GetValue <string>("AWS_SECRET_ACCESS_KEY")) ) ); } builder.AddSingleton <IBlobClient>(sp => new S3BlobClient( sp.GetService <AmazonS3Client>(), s3Options.Buckets[WellknownBuckets.ImportLegacyBucket] ) ); break; case nameof(FileBlobClient): var fileOptions = new FileBlobClientOptions(); hostContext.Configuration.GetSection(nameof(FileBlobClientOptions)).Bind(fileOptions); builder.AddSingleton <IBlobClient>(sp => new FileBlobClient( new DirectoryInfo(fileOptions.Directory) ) ); break; default: throw new Exception(blobOptions.BlobClientType + " is not a supported blob client type."); } var legacyStreamArchiveReader = new LegacyStreamArchiveReader( new JsonSerializerSettings { Formatting = Formatting.Indented, DateFormatHandling = DateFormatHandling.IsoDateFormat, DateTimeZoneHandling = DateTimeZoneHandling.Unspecified, DateParseHandling = DateParseHandling.DateTime, DefaultValueHandling = DefaultValueHandling.Ignore } ); builder .AddSingleton(legacyStreamArchiveReader) .AddSingleton( new SqlConnection( hostContext.Configuration.GetConnectionString(WellknownConnectionNames.Events) ) ) .AddSingleton <IStreamStore>(new MsSqlStreamStore( new MsSqlStreamStoreSettings( hostContext.Configuration.GetConnectionString(WellknownConnectionNames.Events) ) { Schema = WellknownSchemas.EventSchema })) .AddSingleton <LegacyStreamEventsWriter>(); }) .Build(); var configuration = host.Services.GetRequiredService <IConfiguration>(); var logger = host.Services.GetRequiredService <ILogger <Program> >(); var reader = host.Services.GetRequiredService <LegacyStreamArchiveReader>(); var writer = host.Services.GetRequiredService <LegacyStreamEventsWriter>(); var client = host.Services.GetRequiredService <IBlobClient>(); var streamStore = host.Services.GetRequiredService <IStreamStore>(); var blobClientOptions = new BlobClientOptions(); configuration.Bind(blobClientOptions); try { await WaitFor.SeqToBecomeAvailable(configuration).ConfigureAwait(false); logger.LogSqlServerConnectionString(configuration, WellknownConnectionNames.Events); logger.LogBlobClientCredentials(blobClientOptions); await DistributedLock <Program> .RunAsync(async() => { var eventsConnectionStringBuilder = new SqlConnectionStringBuilder( configuration.GetConnectionString(WellknownConnectionNames.Events)); var masterConnectionStringBuilder = new SqlConnectionStringBuilder(eventsConnectionStringBuilder.ConnectionString) { InitialCatalog = "master" }; await WaitFor.SqlServerToBecomeAvailable(masterConnectionStringBuilder, logger).ConfigureAwait(false); await WaitFor.SqlServerDatabaseToBecomeAvailable( masterConnectionStringBuilder, eventsConnectionStringBuilder, logger ).ConfigureAwait(false); if (streamStore is MsSqlStreamStore sqlStreamStore) { await sqlStreamStore.CreateSchema().ConfigureAwait(false); } var page = await streamStore .ReadStreamForwards(RoadNetworks.Stream, StreamVersion.Start, 1) .ConfigureAwait(false); if (page.Status == PageReadStatus.StreamNotFound) { var blob = await client .GetBlobAsync(new BlobName("import-streams.zip"), CancellationToken.None) .ConfigureAwait(false); var watch = Stopwatch.StartNew(); using (var blobStream = await blob.OpenAsync().ConfigureAwait(false)) { await writer .WriteAsync(reader.Read(blobStream)) .ConfigureAwait(false); } logger.LogInformation("Total append took {0}ms", watch.ElapsedMilliseconds); } else { logger.LogWarning( "The road network was previously imported. This can only be performed once."); } }, DistributedLockOptions.LoadFromConfiguration(configuration), logger) .ConfigureAwait(false); } catch (Exception exception) { logger.LogCritical(exception, "Encountered a fatal exception, exiting program."); } finally { Log.CloseAndFlush(); } }
public static async Task Main(string[] args) { var ct = CancellationTokenSource.Token; ct.Register(() => Closing.Set()); Console.CancelKeyPress += (sender, eventArgs) => CancellationTokenSource.Cancel(); AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => Log.Debug( eventArgs.Exception, "FirstChanceException event raised in {AppDomain}.", AppDomain.CurrentDomain.FriendlyName); AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) => Log.Fatal((Exception)eventArgs.ExceptionObject, "Encountered a fatal exception, exiting program."); var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) .AddJsonFile($"appsettings.{Environment.MachineName.ToLowerInvariant()}.json", optional: true, reloadOnChange: false) .AddEnvironmentVariables() .AddCommandLine(args ?? new string[0]) .Build(); var container = ConfigureServices(configuration); var logger = container.GetService <ILogger <Program> >(); logger.LogInformation("Starting Be.Vlaanderen.Basisregisters.Redis.LastChangedList service."); var jsonSettings = JsonSerializerSettingsProvider.CreateSerializerSettings().ConfigureDefaultForApi(); JsonConvert.DefaultSettings = () => jsonSettings; try { await DistributedLock <Program> .RunAsync( async() => { try { var runner = container.GetRequiredService <PopulatorRunner>(); logger.LogInformation("Running... Press CTRL + C to exit."); var timeoutInSeconds = configuration.GetValue <int?>("TaskTimeoutInSeconds") ?? 14400; //4hours (4 * 60 * 60) var task = runner.RunAsync(ct); await task.WaitAsync(TimeSpan.FromSeconds(timeoutInSeconds), ct); if (!task.IsCompletedSuccessfully) { Log.Error("Redis populator timed out. Cancelling task and exiting."); CancellationTokenSource.Cancel(); } } catch (Exception e) { Log.Fatal(e, "Encountered a fatal exception, exiting program."); throw; } }, DistributedLockOptions.LoadFromConfiguration(configuration) ?? DistributedLockOptions.Defaults, container.GetService <ILogger <Program> >()); } catch (Exception e) { // Console.WriteLine(e.ToString()); logger.LogCritical(e, "Encountered a fatal exception, exiting program."); Log.CloseAndFlush(); // Allow some time for flushing before shutdown. Thread.Sleep(1000); throw; } logger.LogInformation("Stopping..."); Closing.Close(); }
public static async Task Main(string[] args) { Console.WriteLine("Starting RoadRegistry.BackOffice.EventHost"); AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => Log.Debug(eventArgs.Exception, "FirstChanceException event raised in {AppDomain}.", AppDomain.CurrentDomain.FriendlyName); AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) => Log.Fatal((Exception)eventArgs.ExceptionObject, "Encountered a fatal exception, exiting program."); var host = new HostBuilder() .ConfigureHostConfiguration(builder => { builder .AddEnvironmentVariables("DOTNET_") .AddEnvironmentVariables("ASPNETCORE_"); }) .ConfigureAppConfiguration((hostContext, builder) => { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); if (hostContext.HostingEnvironment.IsProduction()) { builder .SetBasePath(Directory.GetCurrentDirectory()); } builder .AddJsonFile("appsettings.json", true, false) .AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName.ToLowerInvariant()}.json", true, false) .AddJsonFile($"appsettings.{Environment.MachineName.ToLowerInvariant()}.json", true, false) .AddEnvironmentVariables() .AddCommandLine(args); }) .ConfigureLogging((hostContext, builder) => { Serilog.Debugging.SelfLog.Enable(Console.WriteLine); var loggerConfiguration = new LoggerConfiguration() .ReadFrom.Configuration(hostContext.Configuration) .Enrich.FromLogContext() .Enrich.WithMachineName() .Enrich.WithThreadId() .Enrich.WithEnvironmentUserName(); Log.Logger = loggerConfiguration.CreateLogger(); builder.AddSerilog(Log.Logger); }) .ConfigureServices((hostContext, builder) => { var blobOptions = new BlobClientOptions(); hostContext.Configuration.Bind(blobOptions); switch (blobOptions.BlobClientType) { case nameof(S3BlobClient): var s3Options = new S3BlobClientOptions(); hostContext.Configuration.GetSection(nameof(S3BlobClientOptions)).Bind(s3Options); // Use MINIO if (hostContext.Configuration.GetValue <string>("MINIO_SERVER") != null) { if (hostContext.Configuration.GetValue <string>("MINIO_ACCESS_KEY") == null) { throw new Exception("The MINIO_ACCESS_KEY configuration variable was not set."); } if (hostContext.Configuration.GetValue <string>("MINIO_SECRET_KEY") == null) { throw new Exception("The MINIO_SECRET_KEY configuration variable was not set."); } builder.AddSingleton(new AmazonS3Client( new BasicAWSCredentials( hostContext.Configuration.GetValue <string>("MINIO_ACCESS_KEY"), hostContext.Configuration.GetValue <string>("MINIO_SECRET_KEY")), new AmazonS3Config { RegionEndpoint = RegionEndpoint.USEast1, // minio's default region ServiceURL = hostContext.Configuration.GetValue <string>("MINIO_SERVER"), ForcePathStyle = true } ) ); } else // Use AWS { if (hostContext.Configuration.GetValue <string>("AWS_ACCESS_KEY_ID") == null) { throw new Exception("The AWS_ACCESS_KEY_ID configuration variable was not set."); } if (hostContext.Configuration.GetValue <string>("AWS_SECRET_ACCESS_KEY") == null) { throw new Exception("The AWS_SECRET_ACCESS_KEY configuration variable was not set."); } builder.AddSingleton(new AmazonS3Client( new BasicAWSCredentials( hostContext.Configuration.GetValue <string>("AWS_ACCESS_KEY_ID"), hostContext.Configuration.GetValue <string>("AWS_SECRET_ACCESS_KEY")) ) ); } builder.AddSingleton <IBlobClient>(sp => new S3BlobClient( sp.GetService <AmazonS3Client>(), s3Options.Buckets[WellknownBuckets.UploadsBucket] ) ); break; case nameof(FileBlobClient): var fileOptions = new FileBlobClientOptions(); hostContext.Configuration.GetSection(nameof(FileBlobClientOptions)).Bind(fileOptions); builder.AddSingleton <IBlobClient>(sp => new FileBlobClient( new DirectoryInfo(fileOptions.Directory) ) ); break; default: throw new Exception(blobOptions.BlobClientType + " is not a supported blob client type."); } builder .AddSingleton <Scheduler>() .AddHostedService <EventProcessor>() .AddSingleton <IEventProcessorPositionStore>(sp => new SqlEventProcessorPositionStore( new SqlConnectionStringBuilder( sp.GetService <IConfiguration>().GetConnectionString(WellknownConnectionNames.EventHost) ), WellknownSchemas.EventHostSchema)) .AddSingleton <IStreamStore>(sp => new MsSqlStreamStore( new MsSqlStreamStoreSettings( sp .GetService <IConfiguration>() .GetConnectionString(WellknownConnectionNames.Events) ) { Schema = WellknownSchemas.EventSchema })) .AddSingleton <IClock>(SystemClock.Instance) .AddSingleton(new RecyclableMemoryStreamManager()) .AddSingleton(sp => new RoadNetworkSnapshotReaderWriter( new SqlBlobClient( new SqlConnectionStringBuilder( sp .GetService <IConfiguration>() .GetConnectionString(WellknownConnectionNames.Snapshots) ), WellknownSchemas.SnapshotSchema), sp.GetService <RecyclableMemoryStreamManager>())) .AddSingleton <IRoadNetworkSnapshotReader>(sp => sp.GetRequiredService <RoadNetworkSnapshotReaderWriter>()) .AddSingleton <IRoadNetworkSnapshotWriter>(sp => sp.GetRequiredService <RoadNetworkSnapshotReaderWriter>()) .AddSingleton(sp => new EventHandlerModule[] { new RoadNetworkChangesArchiveEventModule( sp.GetService <IBlobClient>(), new ZipArchiveTranslator(Encoding.UTF8), sp.GetService <IStreamStore>() ), new RoadNetworkEventModule( sp.GetService <IStreamStore>(), sp.GetService <IRoadNetworkSnapshotReader>(), sp.GetService <IRoadNetworkSnapshotWriter>(), sp.GetService <IClock>()) }) .AddSingleton(sp => AcceptStreamMessage.WhenEqualToMessageType(sp.GetRequiredService <EventHandlerModule[]>(), EventProcessor.EventMapping)) .AddSingleton(sp => Dispatch.Using(Resolve.WhenEqualToMessage(sp.GetRequiredService <EventHandlerModule[]>()))); }) .Build(); var configuration = host.Services.GetRequiredService <IConfiguration>(); var streamStore = host.Services.GetRequiredService <IStreamStore>(); var logger = host.Services.GetRequiredService <ILogger <Program> >(); var blobClient = host.Services.GetRequiredService <IBlobClient>(); var blobClientOptions = new BlobClientOptions(); configuration.Bind(blobClientOptions); try { await WaitFor.SeqToBecomeAvailable(configuration).ConfigureAwait(false); logger.LogSqlServerConnectionString(configuration, WellknownConnectionNames.Events); logger.LogSqlServerConnectionString(configuration, WellknownConnectionNames.EventHost); logger.LogSqlServerConnectionString(configuration, WellknownConnectionNames.EventHostAdmin); logger.LogSqlServerConnectionString(configuration, WellknownConnectionNames.Snapshots); logger.LogSqlServerConnectionString(configuration, WellknownConnectionNames.SnapshotsAdmin); logger.LogBlobClientCredentials(blobClientOptions); await DistributedLock <Program> .RunAsync(async() => { await WaitFor.SqlStreamStoreToBecomeAvailable(streamStore, logger).ConfigureAwait(false); await new SqlBlobSchema( new SqlConnectionStringBuilder(configuration.GetConnectionString(WellknownConnectionNames.SnapshotsAdmin)) ).CreateSchemaIfNotExists(WellknownSchemas.SnapshotSchema).ConfigureAwait(false); await new SqlEventProcessorPositionStoreSchema( new SqlConnectionStringBuilder(configuration.GetConnectionString(WellknownConnectionNames.EventHostAdmin)) ).CreateSchemaIfNotExists(WellknownSchemas.EventHostSchema).ConfigureAwait(false); await blobClient.ProvisionResources(host).ConfigureAwait(false); await host.RunAsync().ConfigureAwait(false); }, DistributedLockOptions.LoadFromConfiguration(configuration), logger) .ConfigureAwait(false); } catch (Exception e) { logger.LogCritical(e, "Encountered a fatal exception, exiting program."); } finally { Log.CloseAndFlush(); } }