62 lines
1.9 KiB
C#
62 lines
1.9 KiB
C#
using Microsoft.Extensions.Options;
|
|
using QMax.Api.Configuration;
|
|
|
|
namespace QMax.Api.Services;
|
|
|
|
public sealed class MaxOutboxWorker(
|
|
IServiceScopeFactory scopeFactory,
|
|
IOptions<QMaxOptions> options,
|
|
ILogger<MaxOutboxWorker> logger) : BackgroundService
|
|
{
|
|
private readonly QMaxOptions _options = options.Value;
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
var delay = TimeSpan.FromSeconds(Math.Max(1, _options.MaxOutboxPollIntervalSeconds));
|
|
|
|
await Task.WhenAll(
|
|
RunOutboxLoopAsync(
|
|
"message outbox",
|
|
delay,
|
|
(outbox, cancellationToken) => outbox.ProcessPendingMessagesOnceAsync(cancellationToken),
|
|
stoppingToken),
|
|
RunOutboxLoopAsync(
|
|
"chat command outbox",
|
|
delay,
|
|
(outbox, cancellationToken) => outbox.ProcessPendingChatActionsOnceAsync(cancellationToken),
|
|
stoppingToken));
|
|
}
|
|
|
|
private async Task RunOutboxLoopAsync(
|
|
string workerName,
|
|
TimeSpan delay,
|
|
Func<MaxOutboxService, CancellationToken, Task<int>> process,
|
|
CancellationToken stoppingToken)
|
|
{
|
|
using var timer = new PeriodicTimer(delay);
|
|
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
await timer.WaitForNextTickAsync(stoppingToken);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
break;
|
|
}
|
|
|
|
try
|
|
{
|
|
await using var scope = scopeFactory.CreateAsyncScope();
|
|
var outbox = scope.ServiceProvider.GetRequiredService<MaxOutboxService>();
|
|
await process(outbox, stoppingToken);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.LogWarning(ex, "QMAX {WorkerName} tick failed.", workerName);
|
|
}
|
|
}
|
|
}
|
|
}
|