Редактирование заявок у конкретного пользователя (#14)
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/14
This commit was merged in pull request #14.
This commit is contained in:
@@ -40,20 +40,34 @@ public sealed class ReminderService(
|
||||
.Where(x => x.SlaHours != null && x.ListId != null && x.SiteUrl != null)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
// Типы независимы (разные сайты/списки в SharePoint) — их обход
|
||||
// распараллелен, иначе время растёт линейно с числом типов: каждый тип
|
||||
// сам по себе делает несколько последовательных HTTP-запросов.
|
||||
var results = await Task.WhenAll(types.Select(type => GetOverdueForTypeSafeAsync(type, now, cancellationToken)));
|
||||
// Архивные партиции читаем ПОСЛЕДОВАТЕЛЬНО, одним DbContext — он не
|
||||
// потокобезопасен, и параллельный вызов GetArchivedAsync из нескольких
|
||||
// веток Task.WhenAll ниже валит его исключением ("A second operation
|
||||
// was started on this context instance before a previous operation
|
||||
// completed"), которое try/catch в GetOverdueForTypeSafeAsync тихо
|
||||
// проглатывает — часть напоминаний молча пропадала бы без всякой
|
||||
// видимой ошибки. Сама выборка — без HTTP, быстрая, последовательность
|
||||
// здесь не стоит ощутимого времени.
|
||||
var archivedByType = new Dictionary<int, IReadOnlyList<RequestListPartition>>();
|
||||
foreach (var type in types)
|
||||
archivedByType[type.Id] = await partitionRegistry.GetArchivedAsync(type, cancellationToken);
|
||||
|
||||
// Дальше типы независимы (разные сайты/списки в SharePoint, БД уже не
|
||||
// трогают) — обход распараллелен, иначе время растёт линейно с числом
|
||||
// типов: каждый тип сам по себе делает несколько последовательных
|
||||
// HTTP-запросов.
|
||||
var results = await Task.WhenAll(
|
||||
types.Select(type => GetOverdueForTypeSafeAsync(type, archivedByType[type.Id], now, cancellationToken)));
|
||||
|
||||
return Result.Ok<IReadOnlyList<ReminderDto>>(results.SelectMany(r => r).ToList());
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyList<ReminderDto>> GetOverdueForTypeSafeAsync(
|
||||
RequestType type, DateTimeOffset now, CancellationToken cancellationToken)
|
||||
RequestType type, IReadOnlyList<RequestListPartition> archived, DateTimeOffset now, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await GetOverdueForTypeAsync(type, now, cancellationToken);
|
||||
return await GetOverdueForTypeAsync(type, archived, now, cancellationToken);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -70,14 +84,13 @@ public sealed class ReminderService(
|
||||
/// списке, и не должна пропадать из напоминаний только из-за того, что для
|
||||
/// новых заявок завели следующий список.
|
||||
///
|
||||
/// request_list_partitions хранит только архив (см. ListPartitionRegistry) —
|
||||
/// текущая партиция синтезируется отдельно и добавляется к архиву здесь же,
|
||||
/// а не читается из БД.
|
||||
/// archived — уже прочитан вызывающей стороной (GetOverdueAsync,
|
||||
/// последовательно для всех типов разом) — здесь БД больше не трогаем,
|
||||
/// только HTTP к SharePoint, поэтому вызов можно параллелить по типам.
|
||||
/// </summary>
|
||||
private async Task<IReadOnlyList<ReminderDto>> GetOverdueForTypeAsync(
|
||||
RequestType type, DateTimeOffset now, CancellationToken cancellationToken)
|
||||
RequestType type, IReadOnlyList<RequestListPartition> archived, DateTimeOffset now, CancellationToken cancellationToken)
|
||||
{
|
||||
var archived = await partitionRegistry.GetArchivedAsync(type, cancellationToken);
|
||||
var current = await partitionRegistry.BuildCurrentAsync(type, archived, cancellationToken);
|
||||
|
||||
var partitions = archived
|
||||
|
||||
Reference in New Issue
Block a user