Merge pull request #4 from TimetableDesigner/dev

performance upgrade
This commit is contained in:
2026-01-30 00:10:57 +01:00
committed by GitHub
Unverified

View File

@@ -1,5 +1,6 @@
using System.Text.Json; using System.Text.Json;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@@ -7,17 +8,23 @@ namespace TimetableDesigner.Backend.Events.OutboxPattern;
public class EventOutboxSender<TDbContext> : BackgroundService where TDbContext : DbContext, IEventOutboxDbContext public class EventOutboxSender<TDbContext> : BackgroundService where TDbContext : DbContext, IEventOutboxDbContext
{ {
private readonly IConfiguration _configuration;
private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IEventQueuePublisher _eventQueuePublisher; private readonly IEventQueuePublisher _eventQueuePublisher;
public EventOutboxSender(IServiceScopeFactory serviceScopeFactory, IEventQueuePublisher eventQueuePublisher) public EventOutboxSender(IConfiguration configuration, IServiceScopeFactory serviceScopeFactory, IEventQueuePublisher eventQueuePublisher)
{ {
_configuration = configuration;
_serviceScopeFactory = serviceScopeFactory; _serviceScopeFactory = serviceScopeFactory;
_eventQueuePublisher = eventQueuePublisher; _eventQueuePublisher = eventQueuePublisher;
} }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{ {
IConfigurationSection section = _configuration.GetSection("Workers:EventOutboxSender");
int delayBetweenQueries = section.GetValue("DelayBetweenEmptyQueries", 10);
int limitInSingleQuery = section.GetValue("LimitInSingleQuery", 50);
using (IServiceScope scope = _serviceScopeFactory.CreateScope()) using (IServiceScope scope = _serviceScopeFactory.CreateScope())
using (TDbContext dbContext = scope.ServiceProvider.GetRequiredService<TDbContext>()) using (TDbContext dbContext = scope.ServiceProvider.GetRequiredService<TDbContext>())
{ {
@@ -25,13 +32,15 @@ public class EventOutboxSender<TDbContext> : BackgroundService where TDbContext
while (!stoppingToken.IsCancellationRequested) while (!stoppingToken.IsCancellationRequested)
{ {
Event? eventData = await dbContext.Events.FirstOrDefaultAsync(x => x.LastRetryOn == null, stoppingToken) IAsyncEnumerable<Event>? events = dbContext.Events
?? await dbContext.Events.OrderBy(x => x.LastRetryOn).FirstOrDefaultAsync(stoppingToken); .OrderBy(x => x.LastRetryOn)
.Take(limitInSingleQuery)
.ToAsyncEnumerable();
if (eventData is null) bool any = false;
await foreach (Event eventData in events)
{ {
continue; any = true;
}
Type payloadType = Type.GetType(eventData.PayloadType)!; Type payloadType = Type.GetType(eventData.PayloadType)!;
JsonSerializer.Deserialize(eventData.Payload, payloadType); JsonSerializer.Deserialize(eventData.Payload, payloadType);
@@ -47,7 +56,13 @@ public class EventOutboxSender<TDbContext> : BackgroundService where TDbContext
eventData.LastRetryOn = DateTimeOffset.UtcNow; eventData.LastRetryOn = DateTimeOffset.UtcNow;
eventData.RetryCount++; eventData.RetryCount++;
} }
finally }
if (!any)
{
await Task.Delay(TimeSpan.FromSeconds(delayBetweenQueries), stoppingToken);
}
else
{ {
await dbContext.SaveChangesAsync(stoppingToken); await dbContext.SaveChangesAsync(stoppingToken);
} }