feature: Outbox Relay and Kafka Pipeline

This commit is contained in:
voltsrage
2026-06-16 22:12:46 +08:00
parent de603df151
commit 84d259d10c
18 changed files with 1277 additions and 6 deletions
@@ -96,6 +96,7 @@ public class AlertService : IAlertService
acknowledgedAt = alert.AcknowledgedAt,
note = req.Note
}),
PartitionKey = alert.EncounterId.ToString(),
CreatedAt = DateTimeOffset.UtcNow
});
@@ -1,3 +1,4 @@
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
public class EncounterService : IEncounterService
@@ -41,11 +42,29 @@ public class EncounterService : IEncounterService
throw new ConflictException(
$"Transition to '{targetStatus}' is not permitted from the current status.",
"ILLEGAL_STATUS_TRANSITION");
var previousStatus = encounter.Status;
encounter.Status = targetStatus;
if (targetStatus == EncounterStatus.Discharged)
encounter.DischargedAt = DateTimeOffset.UtcNow;
_db.OutboxEvents.Add(new OutboxEvent
{
Id = Guid.NewGuid(),
Topic = "encounter.status.changed",
Payload = JsonSerializer.Serialize(new
{
encounterId,
patientId = encounter.PatientId,
previousStatus = previousStatus.ToDbString(),
newStatus = targetStatus.ToDbString(),
changedAt = DateTimeOffset.UtcNow
}),
PartitionKey = encounterId.ToString(),
CreatedAt = DateTimeOffset.UtcNow
});
await _db.SaveChangesAsync();
return new EncounterStatusTransitionResult(encounterId, targetStatus);
}
@@ -116,7 +116,7 @@ public class ObservationService : IObservationService
severity = alert.Severity.ToDbString(),
triggeredAt = alert.TriggeredAt,
partitionKey = encounterId.ToString()
}));
}, encounterId.ToString()));
}
// Step 7 — outbox event for the observation (always; Kafka consumer handles warnings)
@@ -131,7 +131,7 @@ public class ObservationService : IObservationService
source = req.Source.ToDbString(),
recordedAt = req.RecordedAt,
partitionKey = encounterId.ToString()
}));
}, encounterId.ToString()));
// Step 8 — COMMIT
await _db.SaveChangesAsync();
@@ -202,11 +202,12 @@ public class ObservationService : IObservationService
return $"{req.ObservationCode} value {req.Value} {req.Unit} is above critical high of {t.CriticalHigh} {req.Unit}.";
}
private static OutboxEvent BuildOutboxEvent(string topic, object payload) => new()
private static OutboxEvent BuildOutboxEvent(string topic, object payload, string partitionKey) => new()
{
Id = Guid.NewGuid(),
Topic = topic,
Payload = JsonSerializer.Serialize(payload),
PartitionKey = partitionKey,
CreatedAt = DateTimeOffset.UtcNow
};