Isolate MAX chat commands from outbox sends

This commit is contained in:
sevenhill
2026-07-05 22:48:05 +03:00
parent dcc74252c6
commit 0106130744
3 changed files with 143 additions and 11 deletions
+34 -3
View File
@@ -16,9 +16,12 @@ public sealed class MaxOutboxService(
IHubContext<QMaxHub> hubContext,
ILogger<MaxOutboxService> logger)
{
private static readonly TimeSpan InitialChatActionRetryDelay = TimeSpan.FromMinutes(10);
private static readonly TimeSpan MaxChatActionRetryDelay = TimeSpan.FromHours(6);
public async Task<int> ProcessOnceAsync(CancellationToken cancellationToken)
{
var processed = await ProcessPendingChatActionsAsync(cancellationToken);
var processed = 0;
var candidates = await db.Messages
.Include(message => message.Chat)
@@ -47,18 +50,20 @@ public sealed class MaxOutboxService(
}
}
return processed;
return processed + await ProcessPendingChatActionsAsync(cancellationToken);
}
private async Task<int> ProcessPendingChatActionsAsync(CancellationToken cancellationToken)
{
var now = DateTimeOffset.UtcNow;
var pending = await db.Chats
.Where(chat => chat.PendingMaxAction != null)
.ToListAsync(cancellationToken);
pending = pending
.Where(chat => IsChatActionDue(chat, now))
.OrderBy(chat => chat.PendingMaxActionRequestedAt ?? chat.UpdatedAt)
.ThenBy(chat => chat.Id)
.Take(10)
.Take(1)
.ToList();
var processed = 0;
@@ -74,6 +79,30 @@ public sealed class MaxOutboxService(
return processed;
}
private static bool IsChatActionDue(Chat chat, DateTimeOffset now)
{
if (chat.PendingMaxActionLastAttemptAt is null)
{
return true;
}
return now - chat.PendingMaxActionLastAttemptAt.Value >= GetChatActionRetryDelay(chat.PendingMaxActionAttempts);
}
private static TimeSpan GetChatActionRetryDelay(int attempts)
{
if (attempts <= 1)
{
return InitialChatActionRetryDelay;
}
var multiplier = Math.Pow(2, Math.Min(attempts - 1, 5));
var retryDelay = TimeSpan.FromTicks((long)(InitialChatActionRetryDelay.Ticks * multiplier));
return retryDelay <= MaxChatActionRetryDelay
? retryDelay
: MaxChatActionRetryDelay;
}
private async Task<bool> ProcessChatActionAsync(Chat chat, CancellationToken cancellationToken)
{
var pendingAction = chat.PendingMaxAction;
@@ -110,6 +139,8 @@ public sealed class MaxOutboxService(
{
chat.PendingMaxAction = null;
chat.PendingMaxActionRequestedAt = null;
chat.PendingMaxActionLastAttemptAt = null;
chat.PendingMaxActionAttempts = 0;
chat.PendingMaxActionError = null;
}
else