396 lines
17 KiB
C#
396 lines
17 KiB
C#
using System.IO;
|
|
using System.Reflection;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.OpenApi.Models;
|
|
using Newtonsoft.Json;
|
|
using MassTransit;
|
|
using LCU.Library.Internal.Configuration;
|
|
using LCU.Library.Internal.LcuMassTransit;
|
|
using LCU.Library.Internal.LcuMassTransitModels;
|
|
using LCU.Library.Internal.Logging;
|
|
using LCU.Library.Internal.Logging.Middleware;
|
|
using LCU.Library.Internal.Logging.Models;
|
|
using LCU.Api.Internal.Dispatcher.Configurations;
|
|
using LCU.Api.Internal.Dispatcher.Consumers;
|
|
using LCU.Api.Internal.Dispatcher.HostedServices;
|
|
using LCU.Api.Internal.Dispatcher.Models;
|
|
using LCU.Api.Internal.Dispatcher.Services;
|
|
using LCU.Api.Internal.Dispatcher.Services.DispatcherOperationServices;
|
|
using LCU.Api.Internal.Dispatcher.Services.QueueServices;
|
|
using LCU.Api.Internal.DispatcherLib.Persistence;
|
|
using LCU.Api.Internal.DispatcherLib.Repositories;
|
|
using LCU.Api.Internal.DispatcherSharedLib;
|
|
using System.Collections.Generic;
|
|
using LCU.Library.Internal.ApiSecurity.Constants;
|
|
using LCU.Library.Internal.ApiSecurity;
|
|
using LCU.Library.Internal.LcuHttpClient;
|
|
using LCU.Api.Internal.Dispatcher.DataAccess;
|
|
|
|
string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
|
|
ApiConfiguration _apiConfiguration;
|
|
|
|
var builder = BuildBuilder(args);
|
|
BuildServicesAndConfigurations(builder);
|
|
BuildAppAndRun(builder);
|
|
|
|
WebApplicationBuilder BuildBuilder(string[] args)
|
|
{
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
builder.Configuration.AddJsonFile("/app/config/environment-appsettings/appsettings.json", optional: true, reloadOnChange: true);
|
|
builder.Configuration.AddJsonFile("/app/config/workload-appsettings/appsettings.json", optional: true, reloadOnChange: true);
|
|
builder.Configuration.AddJsonFile("/vault/secrets/dispatcher-api-database-connection.json", optional: true, reloadOnChange: true);
|
|
builder.Configuration.AddJsonFile("/vault/secrets/dispatcher-api-seq-api-key.json", optional: true, reloadOnChange: true);
|
|
builder.Configuration.AddJsonFile("/vault/secrets/dispatcher-api-rabbitmq-username.json", optional: true, reloadOnChange: true);
|
|
builder.Configuration.AddJsonFile("/vault/secrets/dispatcher-api-rabbitmq-password.json", optional: true, reloadOnChange: true);
|
|
builder.Configuration.AddJsonFile("/vault/secrets/dispatcher-api-external-api-key-set.json", optional: true, reloadOnChange: true);
|
|
builder.Host.UseSerilog();
|
|
return builder;
|
|
}
|
|
|
|
void BuildServicesAndConfigurations(WebApplicationBuilder builder)
|
|
{
|
|
var services = builder.Services;
|
|
var configuration = builder.Configuration;
|
|
services.AddControllers();
|
|
services.AddEndpointsApiExplorer();
|
|
services.AddSwaggerGen();
|
|
services.AddHttpClient();
|
|
|
|
_apiConfiguration = configuration.Bind<ApiConfiguration>(services, "Primary");
|
|
|
|
var connectionsConfiguration = configuration.Bind<ConnectionsConfiguration>(services);
|
|
|
|
var loggerConfiguration = new LoggingConfiguration(_apiConfiguration.AppName,
|
|
_apiConfiguration.SeqApiKey,
|
|
_apiConfiguration.SeqUrl);
|
|
var lcuLogging = new LcuLogging(loggerConfiguration);
|
|
lcuLogging.UseLcuLogging();
|
|
|
|
var connectionConfiguration = MassTransitConfigurationSetUp.AddConnectionConfiguration(ref services, configuration);
|
|
//debugging
|
|
Console.WriteLine(JsonConvert.SerializeObject(connectionConfiguration));
|
|
|
|
var receiveEndpointConfigurations = new ReceiveEndpointConfigurations()
|
|
{
|
|
ExecutionReceiveEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration,
|
|
"ExecutionReceiveEndpoint"),
|
|
CompletionReceiveEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration,
|
|
"CompletionReceiveEndpoint"),
|
|
DetermineOperationReceiveEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration,
|
|
"DetermineOperationReceiveEndpoint"),
|
|
JobFailureReceiveEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration,
|
|
"JobFailureReceiveEndpoint"),
|
|
SendErroredJobAlertReceiveEndpoint = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration,
|
|
"SendErroredJobAlertReceiveEndpoint")
|
|
};
|
|
services.AddSingleton(receiveEndpointConfigurations);
|
|
//debugging
|
|
Console.WriteLine(JsonConvert.SerializeObject(receiveEndpointConfigurations));
|
|
|
|
services.AddCors(options =>
|
|
{
|
|
options.AddPolicy(MyAllowSpecificOrigins,
|
|
builder =>
|
|
{
|
|
builder.WithOrigins(
|
|
_apiConfiguration.CorsAllowedOrigins
|
|
).AllowAnyHeader().AllowAnyMethod();
|
|
});
|
|
});
|
|
|
|
services.AddDbContextPool<AppDbContext>(options =>
|
|
{
|
|
options.UseSqlServer(
|
|
connectionsConfiguration.Sql.DispatcherDb,
|
|
sqlServerOptionsAction: sqlOptions =>
|
|
{
|
|
sqlOptions.EnableRetryOnFailure(
|
|
maxRetryCount: connectionsConfiguration.Sql.SQLOptions.MaxRetryCount,
|
|
maxRetryDelay: connectionsConfiguration.Sql.SQLOptions.MaxRetryDelay,
|
|
errorNumbersToAdd: connectionsConfiguration.Sql.SQLOptions.ErrorNumbersToAdd
|
|
);
|
|
sqlOptions.CommandTimeout(connectionsConfiguration.Sql.SQLOptions.CommandTimeout);
|
|
}
|
|
);
|
|
options.EnableDetailedErrors(connectionsConfiguration.Sql.SQLOptions.EnableDetailedErrors);
|
|
});
|
|
|
|
AddMassTransitServices(ref services, connectionConfiguration, receiveEndpointConfigurations, _apiConfiguration);
|
|
services.AddDispatcherServices(configuration);
|
|
services.AddLCUHttpServices();
|
|
AddServices(services);
|
|
AddRepositories(services);
|
|
AddHostedServices(services);
|
|
|
|
services.AddSwaggerGen(c =>
|
|
{
|
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = $"{_apiConfiguration.AppName}", Version = "v1" });
|
|
|
|
//Add Security Entry Fields In Swagger
|
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
|
{
|
|
{
|
|
new OpenApiSecurityScheme
|
|
{
|
|
Reference = new OpenApiReference
|
|
{
|
|
Id = HeaderKeys.ApiKey, // Must match the "AddSecurityDefinition"
|
|
Type = ReferenceType.SecurityScheme
|
|
}
|
|
},
|
|
new List<string>()
|
|
}
|
|
});
|
|
|
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
|
{
|
|
{
|
|
new OpenApiSecurityScheme
|
|
{
|
|
Reference = new OpenApiReference
|
|
{
|
|
Id = HeaderKeys.Client, // Must match the "AddSecurityDefinition"
|
|
Type = ReferenceType.SecurityScheme
|
|
}
|
|
},
|
|
new List<string>()
|
|
}
|
|
});
|
|
|
|
c.AddSecurityDefinition(HeaderKeys.ApiKey,
|
|
new OpenApiSecurityScheme
|
|
{
|
|
Description = HeaderKeys.ApiKey,
|
|
In = ParameterLocation.Header,
|
|
Name = HeaderKeys.ApiKey,
|
|
Type = SecuritySchemeType.ApiKey,
|
|
Scheme = "apikey"
|
|
});
|
|
|
|
c.AddSecurityDefinition(HeaderKeys.Client,
|
|
new OpenApiSecurityScheme
|
|
{
|
|
Description = HeaderKeys.Client,
|
|
In = ParameterLocation.Header,
|
|
Name = HeaderKeys.Client,
|
|
Type = SecuritySchemeType.ApiKey,
|
|
Scheme = "apikey"
|
|
});
|
|
});
|
|
|
|
builder.Services.AddApiKeySecurity(builder.Configuration);
|
|
}
|
|
|
|
void AddMassTransitServices(ref IServiceCollection services,
|
|
ConnectionConfiguration connectionConfiguration,
|
|
ReceiveEndpointConfigurations receiveEndpointConfigurations,
|
|
ApiConfiguration apiConfiguration)
|
|
{
|
|
services.AddMassTransit(x =>
|
|
{
|
|
x.AddConsumer<ExecutionConsumer>();
|
|
x.AddConsumer<CompletionConsumer>();
|
|
x.AddConsumer<DetermineOperationConsumer>();
|
|
x.AddConsumer<JobFailureConsumer>();
|
|
x.AddConsumer<SendErroredJobAlertConsumer>();
|
|
|
|
x.UsingRabbitMq((context, cfg) =>
|
|
{
|
|
cfg.Host(connectionConfiguration.HostUrl, "/", host =>
|
|
{
|
|
host.Username(connectionConfiguration.UserName);
|
|
host.Password(connectionConfiguration.Password);
|
|
});
|
|
|
|
if (apiConfiguration.FeatureFlags.RunExecutionConsumer)
|
|
{
|
|
cfg.ReceiveEndpoint(receiveEndpointConfigurations.ExecutionReceiveEndpoint.ReceiveEndpoint, e =>
|
|
{
|
|
e.ConfigureConsumer<ExecutionConsumer>(context);
|
|
e.SetQuorumQueue();
|
|
e.PrefetchCount = receiveEndpointConfigurations.CompletionReceiveEndpoint.PrefetchLimit;
|
|
});
|
|
}
|
|
|
|
if (apiConfiguration.FeatureFlags.RunCompletionConsumer)
|
|
{
|
|
cfg.ReceiveEndpoint(receiveEndpointConfigurations.CompletionReceiveEndpoint.ReceiveEndpoint, e =>
|
|
{
|
|
e.ConfigureConsumer<CompletionConsumer>(context);
|
|
e.SetQuorumQueue();
|
|
e.PrefetchCount = receiveEndpointConfigurations.CompletionReceiveEndpoint.PrefetchLimit;
|
|
});
|
|
}
|
|
|
|
if (apiConfiguration.FeatureFlags.RunDetermineOperationConsumer)
|
|
{
|
|
cfg.ReceiveEndpoint(receiveEndpointConfigurations.DetermineOperationReceiveEndpoint.ReceiveEndpoint, e =>
|
|
{
|
|
e.ConfigureConsumer<DetermineOperationConsumer>(context);
|
|
e.SetQuorumQueue();
|
|
e.PrefetchCount = receiveEndpointConfigurations.DetermineOperationReceiveEndpoint.PrefetchLimit;
|
|
});
|
|
}
|
|
|
|
if (apiConfiguration.FeatureFlags.RunJobFailureConsumer)
|
|
{
|
|
cfg.ReceiveEndpoint(receiveEndpointConfigurations.JobFailureReceiveEndpoint.ReceiveEndpoint, e =>
|
|
{
|
|
e.ConfigureConsumer<JobFailureConsumer>(context);
|
|
e.SetQuorumQueue();
|
|
e.PrefetchCount = receiveEndpointConfigurations.JobFailureReceiveEndpoint.PrefetchLimit;
|
|
});
|
|
}
|
|
|
|
if (apiConfiguration.FeatureFlags.RunSendErroredJobAlertConsumer)
|
|
{
|
|
cfg.ReceiveEndpoint(receiveEndpointConfigurations.SendErroredJobAlertReceiveEndpoint.ReceiveEndpoint, e =>
|
|
{
|
|
e.ConfigureConsumer<SendErroredJobAlertConsumer>(context, cons =>
|
|
{
|
|
cons.Options<BatchOptions>(options => options
|
|
.SetMessageLimit(200)
|
|
.SetTimeLimit(5000)
|
|
.SetConcurrencyLimit(1));
|
|
});
|
|
e.SetQuorumQueue();
|
|
e.PrefetchCount = receiveEndpointConfigurations.SendErroredJobAlertReceiveEndpoint.PrefetchLimit;
|
|
});
|
|
}
|
|
});
|
|
});
|
|
services.AddMassTransitHostedService();
|
|
}
|
|
|
|
void AddServices(IServiceCollection services)
|
|
{
|
|
services.AddScoped<IEnvironmentView, EnvironmentView>();
|
|
|
|
AddDispatcherOperationServices(services);
|
|
AddQueueServices(services);
|
|
services.AddScoped<IJobService, JobService>();
|
|
services.AddScoped<IJobTagService, JobTagService>();
|
|
services.AddScoped<ITagService, TagService>();
|
|
services.AddScoped<IWorkItemService, WorkItemService>();
|
|
services.AddScoped<IWorkItemExecutionService, WorkItemExecutionService>();
|
|
services.AddScoped<IExecutionMessageService, ExecutionMessageService>();
|
|
services.AddScoped<IJobErrorRecipientService, JobErrorRecipientService>();
|
|
services.AddScoped<INotificationService, NotificationService>();
|
|
services.AddScoped<ICleanUpJobSettingService, CleanUpJobSettingService>();
|
|
services.AddScoped<ICleanUpJobTagService, CleanUpJobTagService>();
|
|
}
|
|
|
|
void AddDispatcherOperationServices(IServiceCollection services)
|
|
{
|
|
services.AddScoped<IJobScheduleService, JobScheduleService>();
|
|
services.AddScoped<IBatchErroredJobsService, BatchErroredJobsService>();
|
|
services.AddScoped<IIngestionService, IngestionService>();
|
|
services.AddScoped<IExecutionService, ExecutionService>();
|
|
services.AddScoped<ICompletionService, CompletionService>();
|
|
|
|
services.AddScoped<ICleanUpJobsService, CleanUpJobsService>();
|
|
services.AddScoped<IDetermineOperationService, DetermineOperationService >();
|
|
services.AddScoped<IJobFailureService, JobFailureService >();
|
|
services.AddScoped<ISendErroredJobAlertService, SendErroredJobAlertService >();
|
|
}
|
|
|
|
void AddQueueServices(IServiceCollection services)
|
|
{
|
|
services.AddScoped<IQueueExecutionService, QueueExecutionService>();
|
|
services.AddScoped<IQueueCompletionService, QueueCompletionService>();
|
|
services.AddScoped<IQueueSendErroredJobAlertService, QueueSendErroredJobAlertService>();
|
|
services.AddScoped<IQueueDetermineOperationService, QueueDetermineOperationService>();
|
|
services.AddScoped<IQueueJobFailureService, QueueJobFailureService>();
|
|
}
|
|
|
|
void AddRepositories(IServiceCollection services)
|
|
{
|
|
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
|
services.AddScoped<IJobRepository, JobRepository>();
|
|
services.AddScoped<IJobErrorRecipientRepository, JobErrorRecipientRepository>();
|
|
services.AddScoped<IJobTagRepository, JobTagRepository>();
|
|
services.AddScoped<ITagRepository, TagRepository>();
|
|
services.AddScoped<IWorkItemRepository, WorkItemRepository>();
|
|
services.AddScoped<IWorkItemExecutionRepository, WorkItemExecutionRepository>();
|
|
services.AddScoped<IExecutionMessageRepository, ExecutionMessageRepository>();
|
|
services.AddScoped<ICleanUpJobSettingRepository, CleanUpJobSettingRepository>();
|
|
services.AddScoped<ICleanUpJobTagRepository, CleanUpJobTagRepository>();
|
|
services.AddScoped<INotificationsApiDao, NotificationsApiDao>();
|
|
}
|
|
|
|
void AddHostedServices(IServiceCollection services)
|
|
{
|
|
services.AddSingleton<ICleanUpJobsHostedService, CleanUpJobsHostedService>();
|
|
services.AddSingleton<IBatchErroredJobsHostedService, BatchErroredJobsHostedService>();
|
|
services.AddSingleton<IJobSchedulerHostedService, JobSchedulerHostedService>();
|
|
}
|
|
|
|
void BuildAppAndRun(WebApplicationBuilder builder)
|
|
{
|
|
var app = builder.Build();
|
|
|
|
if (_apiConfiguration.FeatureFlags.RunCleanUpJobsHostedService)
|
|
{
|
|
var service = app.Services.GetRequiredService<ICleanUpJobsHostedService>();
|
|
service.StartAsync().Wait();
|
|
}
|
|
|
|
if (_apiConfiguration.FeatureFlags.RunJobSchedulerHostedService)
|
|
{
|
|
var service = app.Services.GetRequiredService<IJobSchedulerHostedService>();
|
|
service.StartAsync().Wait();
|
|
}
|
|
|
|
if (_apiConfiguration.FeatureFlags.RunBatchErroredJobsHostedService)
|
|
{
|
|
var service = app.Services.GetRequiredService<IBatchErroredJobsHostedService>();
|
|
service.StartAsync().Wait();
|
|
}
|
|
|
|
// Configure the HTTP request pipeline.
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.UseDeveloperExceptionPage();
|
|
}
|
|
|
|
app.UseSwagger(c =>
|
|
{
|
|
c.PreSerializeFilters.Add((swaggerDoc, request) =>
|
|
{
|
|
const string prefixHeader = "X-Forwarded-Prefix";
|
|
if (request.Headers.ContainsKey(prefixHeader)) return;
|
|
|
|
var serverUrl = request.Headers[prefixHeader];
|
|
if (!String.IsNullOrWhiteSpace(serverUrl))
|
|
{
|
|
swaggerDoc.Servers = new List<OpenApiServer>()
|
|
{
|
|
new() { Description = serverUrl, Url = serverUrl }
|
|
};
|
|
}
|
|
});
|
|
});
|
|
app.UseSwaggerUI(c =>
|
|
{
|
|
c.RoutePrefix = "swagger";
|
|
c.SwaggerEndpoint("v1/swagger.json", "LCU.Api.Internal.Dispatcher v1");
|
|
});
|
|
app.UseMiddleware<RequestResponseLoggingMiddleware>();
|
|
app.UseSerilogRequestLogging(options =>
|
|
{
|
|
options.EnrichDiagnosticContext = RequestResponseLoggingMiddleware.RequestDataParser.EnrichFromRequest;
|
|
});
|
|
|
|
app.UseRouting();
|
|
app.UseCors(MyAllowSpecificOrigins);
|
|
app.UseHttpsRedirection();
|
|
app.UseAuthorization();
|
|
app.MapControllers();
|
|
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
|
|
|
|
app.Run();
|
|
} |