feature: Warning Alert Consumer, Orders API & Input Validation

This commit is contained in:
voltsrage
2026-06-18 15:57:55 +08:00
parent c0cd75856c
commit 7d9e53fb8d
30 changed files with 2334 additions and 29 deletions
+44 -3
View File
@@ -4,6 +4,10 @@ using Prometheus;
using Serilog;
using StackExchange.Redis;
using System.Text.Json.Serialization;
using FluentValidation;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Mvc;
using System.Reflection;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
@@ -13,6 +17,9 @@ try
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddFluentValidationAutoValidation();
builder.Services.AddValidatorsFromAssemblyContaining<Program>();
// Serilog's reloadable logger can only be frozen once per process; skip in
// integration tests where WebApplicationFactory may build multiple hosts.
if (!builder.Environment.IsEnvironment("Testing"))
@@ -64,13 +71,14 @@ try
builder.Services.AddScoped<IObservationService, ObservationService>();
builder.Services.AddScoped<IObservationQueryService, ObservationQueryService>();
builder.Services.AddScoped<IAlertService, AlertService>();
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddScoped<IAnalyticsService, AnalyticsService>();
builder.Services.AddScoped<SirsDetector>();
builder.Services.AddScoped<UnacknowledgedAlertsCheck>();
builder.Services.AddScoped<PendingOrdersCheck>();
builder.Services.AddScoped<DisconnectedMonitorsCheck>();
builder.Services.AddScoped<ReconciliationPublisher>();
builder.Services.AddScoped<ReconciliationPublisher>();
builder.Services.AddScoped<WarningEvaluator>();
builder.Services.AddHostedService<ThresholdCacheLoader>();
builder.Services.AddHostedService<KafkaTopicProvisioner>();
@@ -88,6 +96,8 @@ try
builder.Services.AddHostedService<OutboxPendingCollector>();
builder.Services.AddHostedService<KafkaConsumerLagCollector>();
builder.Services.AddHostedService<DataLakeWriterService>();
builder.Services.AddHostedService<WarningAlertService>();
builder.Services.AddControllers()
.AddJsonOptions(opts =>
@@ -99,7 +109,38 @@ try
opts.JsonSerializerOptions.Converters.Add(new DepartmentJsonConverter());
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(options =>
{
var xmlPath = Path.Combine(AppContext.BaseDirectory,
$"{Assembly.GetExecutingAssembly().GetName().Name}.xml");
options.IncludeXmlComments(xmlPath);
});
builder.Services.Configure<ApiBehaviorOptions>(options =>
{
options.InvalidModelStateResponseFactory = context =>
{
var errors = context.ModelState
.Where(e => e.Value?.Errors.Count > 0)
.SelectMany(e => e.Value!.Errors.Select(err => new
{
field = e.Key,
message = err.ErrorMessage
}))
.ToList();
var response = ApiResponse<object>.Fail(400,
"One or more validation errors occurred.", "VALIDATION_ERROR");
return new BadRequestObjectResult(new
{
response.Success,
response.StatusCode,
data = (object?)null,
error = new { message = "One or more validation errors occurred.", code = "VALIDATION_ERROR", details = errors }
});
};
});
var app = builder.Build();