initial commit
This commit is contained in:
19
TimetableDesigner.Backend.Events.OutboxPattern/Event.cs
Normal file
19
TimetableDesigner.Backend.Events.OutboxPattern/Event.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace TimetableDesigner.Backend.Events.OutboxPattern;
|
||||
|
||||
public class Event
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public required string Payload { get; set; }
|
||||
public required string PayloadType { get; set; }
|
||||
public DateTimeOffset OccuredOn { get; set; } = DateTimeOffset.UtcNow;
|
||||
public DateTimeOffset? LastRetryOn { get; set; }
|
||||
public uint RetryCount { get; set; }
|
||||
|
||||
public Event(object payload)
|
||||
{
|
||||
Payload = JsonSerializer.Serialize(payload);
|
||||
PayloadType = payload.GetType().FullName!;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace TimetableDesigner.Backend.Events.OutboxPattern;
|
||||
|
||||
public class EventConfiguration : IEntityTypeConfiguration<Event>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Event> builder)
|
||||
{
|
||||
builder.HasKey(x => x.Id);
|
||||
builder.HasIndex(x => x.Id)
|
||||
.IsUnique();
|
||||
builder.Property(x => x.Id)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(x => x.Payload)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(x => x.PayloadType)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(x => x.OccuredOn)
|
||||
.IsRequired();
|
||||
|
||||
builder.Property(x => x.LastRetryOn);
|
||||
|
||||
builder.Property(x => x.RetryCount)
|
||||
.IsRequired();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace TimetableDesigner.Backend.Events.OutboxPattern;
|
||||
|
||||
public class EventOutboxSender<TDbContext> : BackgroundService where TDbContext : DbContext, IEventOutboxDbContext
|
||||
{
|
||||
private readonly TDbContext _databaseContext;
|
||||
private readonly IEventQueuePublisher _eventQueuePublisher;
|
||||
|
||||
public EventOutboxSender(TDbContext databaseContext, IEventQueuePublisher eventQueuePublisher)
|
||||
{
|
||||
_databaseContext = databaseContext;
|
||||
_eventQueuePublisher = eventQueuePublisher;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
Event? eventData = await _databaseContext.Events.FirstOrDefaultAsync(x => x.LastRetryOn == null, stoppingToken)
|
||||
?? await _databaseContext.Events.OrderBy(x => x.LastRetryOn).FirstOrDefaultAsync(stoppingToken);
|
||||
|
||||
if (eventData is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Type payloadType = Type.GetType(eventData.PayloadType)!;
|
||||
JsonSerializer.Deserialize(eventData.Payload, payloadType);
|
||||
|
||||
try
|
||||
{
|
||||
await _eventQueuePublisher.PublishAsync(eventData.Payload, payloadType);
|
||||
|
||||
_databaseContext.Events.Remove(eventData);
|
||||
}
|
||||
catch
|
||||
{
|
||||
eventData.LastRetryOn = DateTimeOffset.UtcNow;
|
||||
eventData.RetryCount++;
|
||||
}
|
||||
finally
|
||||
{
|
||||
await _databaseContext.SaveChangesAsync(stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace TimetableDesigner.Backend.Events.OutboxPattern;
|
||||
|
||||
public interface IEventOutboxDbContext
|
||||
{
|
||||
DbSet<Event> Events { get; }
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version />
|
||||
<Title>TimetableDesigner.Backend.Events.OutboxPattern</Title>
|
||||
<Authors>Mateusz Skoczek</Authors>
|
||||
<PackageProjectUrl>https://github.com/TimetableDesigner</PackageProjectUrl>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<RepositoryUrl>https://github.com/TimetableDesigner/TimetableDesigner.Backend.Events.OutboxPattern</RepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.2" />
|
||||
<PackageReference Include="TimetableDesigner.Backend.Events" Version="1.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
BIN
TimetableDesigner.Backend.Events.OutboxPattern/icon.png
Normal file
BIN
TimetableDesigner.Backend.Events.OutboxPattern/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Reference in New Issue
Block a user