feat(infrastructure): implement IEmailSyncService on EmailSyncWorker with rate-limited ForceTriggerSync via IMemoryCache; register as singleton in DI

This commit is contained in:
2026-08-17 16:05:30 +02:00
parent c189a2d6ef
commit 8925428e46
2 changed files with 22 additions and 3 deletions

View File

@@ -13,6 +13,7 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace DigitalData.MessagingService.Infrastructure;
@@ -71,6 +72,13 @@ public static class DependencyInjection
services.AddHostedService<AsyncInitWorker>();
services.AddHostedService<EmailSyncWorker>();
services.AddSingleton<IEmailSyncService>(p =>
{
var hostedServices = p.GetRequiredService<IEnumerable<IHostedService>>();
var emailSyncWorkers = hostedServices.OfType<EmailSyncWorker>();
return emailSyncWorkers.FirstOrDefault() ?? throw new InvalidOperationException("EmailSyncWorker is not registered.");
});
services.AddMemoryCache();
// --- Database (InMemory) ---

View File

@@ -3,6 +3,7 @@ using DigitalData.MessagingService.Application.Common.Interfaces.Repositories;
using DigitalData.MessagingService.Application.Common.Options;
using DigitalData.MessagingService.Domain.Entities;
using DigitalData.MessagingService.Domain.Enums;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@@ -10,8 +11,10 @@ using Microsoft.Extensions.Options;
namespace DigitalData.MessagingService.Infrastructure.Services.Background;
public class EmailSyncWorker(IOptions<EmailAccountsOptions> Options, IServiceProvider Provider, ILogger<EmailSyncWorker> Logger) : BackgroundService
public class EmailSyncWorker(IOptions<EmailAccountsOptions> Options, IServiceProvider Provider, ILogger<EmailSyncWorker> Logger, IMemoryCache Cache) : BackgroundService, IEmailSyncService
{
private static string ForcedSyncDateCacheKey => $"{nameof(EmailSyncWorker)}_TriggerSync";
private readonly string DefaultFolder = "INBOX";
/// <summary>
@@ -26,7 +29,15 @@ public class EmailSyncWorker(IOptions<EmailAccountsOptions> Options, IServicePro
/// Safe to call from any thread or HTTP request at any time.
/// If a sync is already running, the trigger is ignored — the next cycle starts normally.
/// </summary>
public void TriggerSync() => _syncTrigger.TrySetResult(true);
public DateTime ForceTriggerSync()
{
return Cache.GetOrCreate(ForcedSyncDateCacheKey, e =>
{
e.SetAbsoluteExpiration(TimeSpan.FromSeconds(Options.Value.ForcedSyncIntervalSeconds));
_syncTrigger.TrySetResult(true);
return DateTime.UtcNow;
});
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
@@ -98,7 +109,7 @@ public class EmailSyncWorker(IOptions<EmailAccountsOptions> Options, IServicePro
}
}
public async Task UpsertSeedEmailAccount(CancellationToken stoppingToken)
private async Task UpsertSeedEmailAccount(CancellationToken stoppingToken)
{
await using var scope = Provider.CreateAsyncScope();