示例#1
0
 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)
     }
 });
示例#2
0
        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();
        }
示例#3
0
        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();
            }
        }
示例#4
0
        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();
        }
示例#6
0
        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();
            }
        }