Added Mediator and Quartz components

This commit is contained in:
2026-08-20 16:32:13 +02:00
parent eef9ade66d
commit f4c680d19d
11 changed files with 382 additions and 4 deletions
@@ -2,6 +2,8 @@ namespace PostFundManagement.Domain.Extensions;
public static class Constants
{
public const string DatabaseConfigName = "PfmDatabase";
public const int LabelLength = 256;
public const int ShortLabelLength = 100;
@@ -0,0 +1,15 @@
using System.Diagnostics;
using System.Diagnostics.Metrics;
namespace PostFundManagement.Domain.Extensions;
public static class MediatorTelemetry
{
public const string ServiceName = "LiteCharms.Mediator";
public static readonly ActivitySource Source = new(ServiceName);
public static readonly Meter Meter = new(ServiceName);
public static readonly Counter<long> RequestCounter = Meter.CreateCounter<long>("mediator_requests_total");
public static readonly Histogram<double> RequestDuration = Meter.CreateHistogram<double>("mediator_request_duration_ms");
}
@@ -0,0 +1,104 @@
using PostFundManagement.Domain.Abstractions;
using PostFundManagement.Domain.Quartz;
using static PostFundManagement.Domain.Extensions.Constants;
namespace PostFundManagement.Domain.Extensions;
public static class Quartz
{
public const string DefaultSchedulerName = "tech-shop";
public static IServiceCollection AddQuartzSchedulerClient(this IServiceCollection services, string schedulerName, IConfiguration configuration)
{
var connectionString = configuration.GetConnectionString(DatabaseConfigName);
services.ConfigureCommon();
services.AddQuartz(config =>
{
config.SchedulerName = schedulerName;
config.SchedulerId = "AUTO";
config.UseSimpleTypeLoader();
config.UseDefaultThreadPool(options => options.MaxConcurrency = 0);
config.UseTimeZoneConverter();
config.UsePersistentStore(storage =>
{
storage.PerformSchemaValidation = false;
storage.UseSystemTextJsonSerializer();
storage.SetProperty("quartz.jobStore.clustered", "true");
storage.SetProperty("quartz.jobStore.tablePrefix", "qrtz_");
storage.UsePostgres(connectionString!);
storage.UseClustering(cluster =>
{
cluster.CheckinInterval = TimeSpan.FromSeconds(30);
cluster.CheckinMisfireThreshold = TimeSpan.FromSeconds(90);
});
});
});
return services;
}
public static IServiceCollection AddQuartzScheduler(this IServiceCollection services, string schedulerName, IConfiguration configuration)
{
var connectionString = configuration.GetConnectionString(DatabaseConfigName);
services.ConfigureCommon();
services.AddQuartzHostedService(options => options.WaitForJobsToComplete = true);
services.AddQuartz(config =>
{
config.SchedulerName = schedulerName;
config.SchedulerId = "AUTO";
config.InterruptJobsOnShutdown = true;
config.InterruptJobsOnShutdownWithWait = true;
config.MaxBatchSize = 5;
config.UseSimpleTypeLoader();
config.UseDefaultThreadPool(options => options.MaxConcurrency = 1);
config.UseTimeZoneConverter();
config.SetProperty("quartz.jobStore.misfireThreshold", TimeSpan.FromMinutes(2).TotalMilliseconds.ToString(CultureInfo.InvariantCulture));
config.UsePersistentStore(storage =>
{
storage.PerformSchemaValidation = false;
storage.UseSystemTextJsonSerializer();
storage.SetProperty("quartz.jobStore.clustered", "true");
storage.SetProperty("quartz.jobStore.tablePrefix", "qrtz_");
storage.UsePostgres(connectionString!);
storage.UseClustering(cluster =>
{
cluster.CheckinInterval = TimeSpan.FromSeconds(30);
cluster.CheckinMisfireThreshold = TimeSpan.FromSeconds(90);
});
});
});
return services;
}
private static IServiceCollection ConfigureCommon(this IServiceCollection services)
{
services.Configure<QuartzOptions>(options =>
{
options.Scheduling.IgnoreDuplicates = true;
options.Scheduling.OverWriteExistingData = true;
options["quartz.plugin.jobHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin, Quartz.Plugins";
options["quartz.plugin.triggerHistory.type"] = "Quartz.Plugin.History.LoggingTriggerHistoryPlugin, Quartz.Plugins";
});
services.AddTransient<RetryJobListener>();
services.AddTransient<IJobOrchestrator, JobOrchestrator>();
return services;
}
}