Почистить комментарии от упоминаний процесса
Удалены <remarks>, <summary> сжаты до короткой фразы, вырезаны ссылки на Task/Ruling/этап/python/прототип; //-комментарии со ссылками на процесс удалены; то же в .proto. Правила обновлены в docs/spec/Код-стайл-Дейл.md. Строк комментариев 27210 -> ~19100.
This commit is contained in:
@@ -7,42 +7,32 @@ using Deal.Telegram.Telegram;
|
||||
namespace Deal.Telegram.Dialogs;
|
||||
|
||||
/// <summary>
|
||||
/// Backfill диалога: перечитывание последних ~10 сообщений и отправка их в ядро потоком PushMessage
|
||||
/// (план Task 10, Dialogs/BackfillService.cs; прототип backfill_dialog/_backfill_dialogs L331–390).
|
||||
///
|
||||
/// 1:1 с прототипом: сообщения читаются от старых к новым (reversed — как реальный поток), между
|
||||
/// отправками — анти-бан-пауза 1.5–3 с/сообщение (Ruling 3, BACKFILL_PER_MESSAGE L35); между
|
||||
/// диалогами одного тенанта — пауза 3–6 с (BACKFILL_PER_DIALOG L36, python sleep между диалогами
|
||||
/// L347). В конце — read-ack (снять «новое» в Telegram). Ошибка середины потока прерывает backfill
|
||||
/// без read-ack: сообщения, не дошедшие до ядра, останутся непрочитанными и будут догнаны
|
||||
/// realtime_sweep; дубли уже доставленных в ядро не растут (дубль-гвард dialog+msgId, Ruling 7).
|
||||
/// Параметр force («Перечитать» по кнопке) прототип использует против своего флага backfilled;
|
||||
/// в разделении флаг живёт в БД ядра, поэтому RPC исполняется всегда — дубли гасит ядро.
|
||||
/// Backfill диалога
|
||||
/// </summary>
|
||||
public sealed class BackfillService
|
||||
{
|
||||
/// <summary>
|
||||
/// Сколько последних сообщений читает backfill (прототип: limit=10, L371).
|
||||
/// Сколько последних сообщений читает backfill.
|
||||
/// </summary>
|
||||
public const int MessagesLimit = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Нижняя граница анти-бан-паузы между сообщениями (BACKFILL_PER_MESSAGE, L35).
|
||||
/// Нижняя граница анти-бан-паузы между сообщениями.
|
||||
/// </summary>
|
||||
public const double MinPerMessageDelaySeconds = 1.5;
|
||||
|
||||
/// <summary>
|
||||
/// Верхняя граница анти-бан-паузы между сообщениями (BACKFILL_PER_MESSAGE, L35).
|
||||
/// Верхняя граница анти-бан-паузы между сообщениями.
|
||||
/// </summary>
|
||||
public const double MaxPerMessageDelaySeconds = 3.0;
|
||||
|
||||
/// <summary>
|
||||
/// Нижняя граница паузы между диалогами одного тенанта (BACKFILL_PER_DIALOG, L36).
|
||||
/// Нижняя граница паузы между диалогами одного тенанта.
|
||||
/// </summary>
|
||||
public const double MinPerDialogDelaySeconds = 3.0;
|
||||
|
||||
/// <summary>
|
||||
/// Верхняя граница паузы между диалогами одного тенанта (BACKFILL_PER_DIALOG, L36).
|
||||
/// Верхняя граница паузы между диалогами одного тенанта.
|
||||
/// </summary>
|
||||
public const double MaxPerDialogDelaySeconds = 6.0;
|
||||
|
||||
@@ -51,10 +41,8 @@ public sealed class BackfillService
|
||||
private readonly IBackfillPacer _pacer;
|
||||
private readonly ILogger<BackfillService> _logger;
|
||||
|
||||
// Гард повторного входа: (тенант, диалог) уже перечитывается (python `_backfilling` L99).
|
||||
private readonly ConcurrentDictionary<(string TenantId, string DialogId), byte> _running = new();
|
||||
|
||||
// Сериализация backfill'ов одного тенанта (python: один asyncio-loop на все диалоги).
|
||||
private readonly ConcurrentDictionary<string, SemaphoreSlim> _tenantGates = new(StringComparer.Ordinal);
|
||||
|
||||
// Момент завершения последнего backfill тенанта (пауза 3–6 с между диалогами).
|
||||
@@ -82,7 +70,7 @@ public sealed class BackfillService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Перечитывает последние сообщения диалога в ядро (Backfill RPC; кнопка «Перечитать»).
|
||||
/// Перечитывает последние сообщения диалога в ядро
|
||||
/// </summary>
|
||||
/// <param name="tenantId">Id тенанта.</param>
|
||||
/// <param name="dialogId">Подписанный id диалога.</param>
|
||||
@@ -98,7 +86,6 @@ public sealed class BackfillService
|
||||
var key = (tenantId, dialogId);
|
||||
if (!_running.TryAdd(key, 0))
|
||||
{
|
||||
// Прототип L355–356: повторный вход в уже перечитываемый диалог → 0.
|
||||
_logger.LogInformation("Аудит: backfill {TenantId} {DialogId} → пропущен (уже перечитывается)", tenantId, dialogId);
|
||||
return 0;
|
||||
}
|
||||
@@ -135,7 +122,6 @@ public sealed class BackfillService
|
||||
}
|
||||
}
|
||||
|
||||
// Пауза 3–6 с между backfill'ами разных диалогов одного тенанта (python L347).
|
||||
// tenantId: Id тенанта.
|
||||
// cancellationToken: Отмена операции.
|
||||
private async Task EnsureDialogSpacingAsync(string tenantId, CancellationToken cancellationToken)
|
||||
@@ -184,7 +170,6 @@ public sealed class BackfillService
|
||||
int processed = 0;
|
||||
foreach (TelegramMessage message in messages.Reverse())
|
||||
{
|
||||
// От старых к новым — как реальный поток (прототип L372: `for m in reversed(msgs)`).
|
||||
PushMessageReply reply = await _ingress
|
||||
.PushMessageAsync(tenantId, DialogProtoMapper.ToPushRequest(message), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
@@ -193,11 +178,9 @@ public sealed class BackfillService
|
||||
processed++;
|
||||
}
|
||||
|
||||
// Анти-бан между сообщениями (прототип L381; Ruling 3).
|
||||
await _pacer.WaitAsync(MinPerMessageDelaySeconds, MaxPerMessageDelaySeconds, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// «Перечитали» — снимаем «новое» в Telegram (прототип L383–386). При ошибке выше read-ack
|
||||
// не выполняется: неотправленное останется непрочитанным и догонится realtime_sweep.
|
||||
await _sessionFarm.MarkReadAsync(tenantId, dialogId, cancellationToken).ConfigureAwait(false);
|
||||
return processed;
|
||||
|
||||
Reference in New Issue
Block a user