feature: Reconciliation Jobs

This commit is contained in:
voltsrage
2026-06-17 14:36:10 +08:00
parent 56d052aa4f
commit 101040f9d9
40 changed files with 2845 additions and 32 deletions
@@ -9,6 +9,7 @@ public sealed class RabbitMqTopologyProvisioner : IHostedService
public const string PagingKey = "alerts.paging";
public const string EscalKey = "alerts.escalation";
public const string DischargeKey = "notifications.discharge";
public const string ReconciliationKey = "notifications.reconciliation";
private readonly RabbitMqOptions _opts;
private readonly IHostEnvironment _env;
@@ -30,7 +31,7 @@ public sealed class RabbitMqTopologyProvisioner : IHostedService
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
if (_env.IsEnvironment("Testing"))
if (_env.IsDevelopment() || _env.IsEnvironment("Testing"))
{
// Use a throwaway channel — a failed purge on a missing queue closes the
// channel, which would break the declare calls below.
@@ -38,8 +39,8 @@ public sealed class RabbitMqTopologyProvisioner : IHostedService
try
{
// Dev runs provision the DLQ with a 5-minute TTL; delete it so the
// test timeout (5 s) is applied when the queue is re-declared below.
// x-message-ttl is immutable once the queue exists. Integration tests
// use 5 s while local dev uses 5 min — delete so config drives the TTL.
cleanup.QueueDelete("alerts.paging.dlq", ifUnused: false, ifEmpty: false);
}
catch (OperationInterruptedException ex)
@@ -47,12 +48,15 @@ public sealed class RabbitMqTopologyProvisioner : IHostedService
_logger.LogDebug(ex, "DLQ delete skipped — queue may not exist yet");
}
foreach (var queue in new[] { "alerts.paging.queue", "alerts.escalation.queue" })
if (_env.IsEnvironment("Testing"))
{
try { cleanup.QueuePurge(queue); }
catch (OperationInterruptedException ex)
foreach (var queue in new[] { "alerts.paging.queue", "alerts.escalation.queue" })
{
_logger.LogDebug(ex, "Queue purge skipped for {Queue}", queue);
try { cleanup.QueuePurge(queue); }
catch (OperationInterruptedException ex)
{
_logger.LogDebug(ex, "Queue purge skipped for {Queue}", queue);
}
}
}
}
@@ -119,6 +123,14 @@ public sealed class RabbitMqTopologyProvisioner : IHostedService
arguments: null);
channel.QueueBind("notifications.appointment.queue", Exchange, "notifications.appointment");
channel.QueueDeclare(
queue: "notifications.reconciliation.queue",
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
channel.QueueBind("notifications.reconciliation.queue", Exchange, ReconciliationKey);
_logger.LogInformation(
"RabbitMQ topology provisioned. Exchange={Exchange} PagingDlqTtlMs={Ttl}",
Exchange, _opts.PagingAckTimeoutMs);