@ -1,119 +1,25 @@ | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; | |||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; | |||||
using Microsoft.Extensions.Diagnostics.HealthChecks; | |||||
using RabbitMQ.Client; | |||||
namespace Ordering.BackgroundTasks.Extensions; | |||||
namespace Ordering.BackgroundTasks.Extensions | |||||
public static class CustomExtensionMethods | |||||
{ | { | ||||
public static class CustomExtensionMethods | |||||
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration) | |||||
{ | { | ||||
public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
var hcBuilder = services.AddHealthChecks(); | |||||
hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy()); | |||||
hcBuilder.AddSqlServer( | |||||
configuration["ConnectionString"], | |||||
name: "OrderingTaskDB-check", | |||||
tags: new string[] { "orderingtaskdb" }); | |||||
var hcBuilder = services.AddHealthChecks(); | |||||
if (configuration.GetValue<bool>("AzureServiceBusEnabled")) | |||||
{ | |||||
hcBuilder.AddAzureServiceBusTopic( | |||||
configuration["EventBusConnection"], | |||||
topicName: "eshop_event_bus", | |||||
name: "orderingtask-servicebus-check", | |||||
tags: new string[] { "servicebus" }); | |||||
} | |||||
else | |||||
{ | |||||
hcBuilder.AddRabbitMQ( | |||||
$"amqp://{configuration["EventBusConnection"]}", | |||||
name: "orderingtask-rabbitmqbus-check", | |||||
tags: new string[] { "rabbitmqbus" }); | |||||
} | |||||
hcBuilder.AddSqlServer(_ => | |||||
configuration.GetRequiredConnectionString("OrderingDb"), | |||||
name: "OrderingTaskDB-check", | |||||
tags: new string[] { "live", "ready" }); | |||||
return services; | |||||
} | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) | |||||
public static IServiceCollection AddApplicationOptions(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
return services.Configure<BackgroundTaskSettings>(configuration) | |||||
.Configure<BackgroundTaskSettings>(o => | |||||
{ | { | ||||
var subscriptionClientName = configuration["SubscriptionClientName"]; | |||||
if (configuration.GetValue<bool>("AzureServiceBusEnabled")) | |||||
{ | |||||
services.AddSingleton<IServiceBusPersisterConnection>(sp => | |||||
{ | |||||
var serviceBusConnectionString = configuration["EventBusConnection"]; | |||||
return new DefaultServiceBusPersisterConnection(serviceBusConnectionString); | |||||
}); | |||||
services.AddSingleton<IEventBus, EventBusServiceBus>(sp => | |||||
{ | |||||
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); | |||||
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); | |||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); | |||||
string subscriptionName = configuration["SubscriptionClientName"]; | |||||
return new EventBusServiceBus(serviceBusPersisterConnection, logger, eventBusSubcriptionsManager, sp, subscriptionName); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
services.AddSingleton<IRabbitMQPersistentConnection>(sp => | |||||
{ | |||||
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>(); | |||||
var factory = new ConnectionFactory() | |||||
{ | |||||
HostName = configuration["EventBusConnection"], | |||||
DispatchConsumersAsync = true | |||||
}; | |||||
if (!string.IsNullOrEmpty(configuration["EventBusUserName"])) | |||||
{ | |||||
factory.UserName = configuration["EventBusUserName"]; | |||||
} | |||||
if (!string.IsNullOrEmpty(configuration["EventBusPassword"])) | |||||
{ | |||||
factory.Password = configuration["EventBusPassword"]; | |||||
} | |||||
var retryCount = 5; | |||||
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) | |||||
{ | |||||
retryCount = int.Parse(configuration["EventBusRetryCount"]); | |||||
} | |||||
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); | |||||
}); | |||||
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp => | |||||
{ | |||||
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>(); | |||||
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>(); | |||||
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); | |||||
var retryCount = 5; | |||||
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) | |||||
{ | |||||
retryCount = int.Parse(configuration["EventBusRetryCount"]); | |||||
} | |||||
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, sp, eventBusSubcriptionsManager, subscriptionClientName, retryCount); | |||||
}); | |||||
} | |||||
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); | |||||
return services; | |||||
} | |||||
o.ConnectionString = configuration.GetRequiredConnectionString("OrderingDb"); | |||||
}); | |||||
} | } | ||||
} | } |
@ -1,13 +1,10 @@ | |||||
global using Microsoft.AspNetCore.Hosting; | |||||
global using Microsoft.Extensions.Configuration; | |||||
global using Microsoft.Extensions.Hosting; | |||||
global using Ordering.BackgroundTasks.Extensions; | |||||
global using System.IO; | |||||
global using HealthChecks.UI.Client; | |||||
global using System; | |||||
global using Microsoft.AspNetCore.Builder; | global using Microsoft.AspNetCore.Builder; | ||||
global using Microsoft.AspNetCore.Diagnostics.HealthChecks; | |||||
global using Microsoft.Extensions.Configuration; | |||||
global using Microsoft.Extensions.DependencyInjection; | global using Microsoft.Extensions.DependencyInjection; | ||||
global using Microsoft.Extensions.Hosting; | |||||
global using Microsoft.Extensions.Logging; | global using Microsoft.Extensions.Logging; | ||||
global using Ordering.BackgroundTasks.Services; | |||||
global using System; | |||||
global using Ordering.BackgroundTasks; | global using Ordering.BackgroundTasks; | ||||
global using Ordering.BackgroundTasks.Extensions; | |||||
global using Ordering.BackgroundTasks.Services; | |||||
global using Services.Common; |
@ -1,32 +1,18 @@ | |||||
var builder = WebApplication.CreateBuilder(new WebApplicationOptions | |||||
{ | |||||
Args = args, | |||||
ApplicationName = typeof(Program).Assembly.FullName | |||||
}); | |||||
builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()); | |||||
builder.Configuration.AddJsonFile("appsettings.json", optional: true); | |||||
builder.Configuration.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true); | |||||
builder.Configuration.AddEnvironmentVariables(); | |||||
builder.Services.AddCustomHealthCheck(builder.Configuration) | |||||
.Configure<BackgroundTaskSettings>(builder.Configuration) | |||||
.AddHostedService<GracePeriodManagerService>() | |||||
.AddEventBus(builder.Configuration); | |||||
var builder = WebApplication.CreateBuilder(args); | |||||
builder.AddServiceDefaults(); | |||||
builder.Services.AddHealthChecks(builder.Configuration); | |||||
builder.Services.AddApplicationOptions(builder.Configuration); | |||||
builder.Services.AddHostedService<GracePeriodManagerService>(); | |||||
var app = builder.Build(); | var app = builder.Build(); | ||||
if (!app.Environment.IsDevelopment()) | |||||
if (!await app.CheckHealthAsync()) | |||||
{ | { | ||||
app.UseExceptionHandler("/Home/Error"); | |||||
return; | |||||
} | } | ||||
app.UseRouting(); | |||||
app.MapHealthChecks("/hc", new HealthCheckOptions() | |||||
{ | |||||
Predicate = _ => true, | |||||
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse | |||||
}); | |||||
app.MapHealthChecks("/liveness", new HealthCheckOptions | |||||
{ | |||||
Predicate = r => r.Name.Contains("self") | |||||
}); | |||||
app.UseServiceDefaults(); | |||||
await app.RunAsync(); | await app.RunAsync(); |
@ -1,14 +1,17 @@ | |||||
{ | { | ||||
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;", | |||||
"SubscriptionClientName": "BackgroundTasks", | |||||
"GracePeriodTime": "1", | |||||
"CheckUpdateTime": "1000", | |||||
"ApplicationInsights": { | |||||
"InstrumentationKey": "" | |||||
"Logging": { | |||||
"LogLevel": { | |||||
"Default": "Information", | |||||
"Microsoft.AspNetCore": "Warning" | |||||
} | |||||
}, | |||||
"ConnectionStrings": { | |||||
"EventBus": "localhost" | |||||
}, | }, | ||||
"AzureServiceBusEnabled": false, | |||||
"EventBusRetryCount": 5, | |||||
"EventBusConnection": "", | |||||
"EventBusUserName": "", | |||||
"EventBusPassword": "" | |||||
"EventBus": { | |||||
"SubscriptionClientName": "BackgroundTasks", | |||||
"RetryCount": 5 | |||||
}, | |||||
"GracePeriodTime": "1", | |||||
"CheckUpdateTime": "1000" | |||||
} | } |
@ -1,16 +1,17 @@ | |||||
global using Microsoft.AspNetCore.Authentication.JwtBearer; | |||||
global using System; | |||||
global using System.Collections.Generic; | |||||
global using System.Threading.Tasks; | |||||
global using Microsoft.AspNetCore.Authentication.JwtBearer; | |||||
global using Microsoft.AspNetCore.Authorization; | global using Microsoft.AspNetCore.Authorization; | ||||
global using Microsoft.AspNetCore.Builder; | global using Microsoft.AspNetCore.Builder; | ||||
global using Microsoft.AspNetCore.SignalR; | global using Microsoft.AspNetCore.SignalR; | ||||
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
global using Microsoft.eShopOnContainers.Services.Ordering.SignalrHub.IntegrationEvents.Events; | |||||
global using Microsoft.eShopOnContainers.Services.Ordering.SignalrHub; | |||||
global using Microsoft.eShopOnContainers.Services.Ordering.SignalrHub.IntegrationEvents; | global using Microsoft.eShopOnContainers.Services.Ordering.SignalrHub.IntegrationEvents; | ||||
global using Microsoft.eShopOnContainers.Services.Ordering.SignalrHub.IntegrationEvents.EventHandling; | |||||
global using Microsoft.eShopOnContainers.Services.Ordering.SignalrHub.IntegrationEvents.Events; | |||||
global using Microsoft.Extensions.Configuration; | global using Microsoft.Extensions.Configuration; | ||||
global using Microsoft.Extensions.DependencyInjection; | global using Microsoft.Extensions.DependencyInjection; | ||||
global using Microsoft.Extensions.Logging; | global using Microsoft.Extensions.Logging; | ||||
global using Microsoft.eShopOnContainers.Services.Ordering.SignalrHub.IntegrationEvents.EventHandling; | |||||
global using Microsoft.eShopOnContainers.Services.Ordering.SignalrHub; | |||||
global using System.Collections.Generic; | |||||
global using System.Threading.Tasks; | |||||
global using System; | |||||
global using Services.Common; |
@ -0,0 +1,10 @@ | |||||
namespace Microsoft.Extensions.Configuration; | |||||
public static class ConfigurationExtensions | |||||
{ | |||||
public static string GetRequiredValue(this IConfiguration configuration, string name) => | |||||
configuration[name] ?? throw new InvalidOperationException($"Configuration missing value for: {(configuration is IConfigurationSection s ? s.Path + ":" + name : name)}"); | |||||
public static string GetRequiredConnectionString(this IConfiguration configuration, string name) => | |||||
configuration.GetConnectionString(name) ?? throw new InvalidOperationException($"Configuration missing value for: {(configuration is IConfigurationSection s ? s.Path + ":ConnectionStrings:" + name : "ConnectionStrings:" + name)}"); | |||||
} |