Fix/by approver silent failures #25
@@ -152,13 +152,21 @@ public sealed class RequestManageService(
|
|||||||
var statusFilter = string.Join(" or ", activeStatuses.Select(s => $"{StatusField} eq '{Escape(s)}'"));
|
var statusFilter = string.Join(" or ", activeStatuses.Select(s => $"{StatusField} eq '{Escape(s)}'"));
|
||||||
var email = approverEmail.Trim();
|
var email = approverEmail.Trim();
|
||||||
|
|
||||||
|
// DbContext не потокобезопасен: архивные партиции читаем из БД ПОСЛЕДОВАТЕЛЬНО,
|
||||||
|
// и только дальнейшее чтение SharePoint (без БД) идёт параллельно. Раньше
|
||||||
|
// GetArchivedAsync вызывался из параллельных задач — «вторая операция на
|
||||||
|
// контексте» падала, а пустой catch превращал это в пустой список.
|
||||||
|
var archivedByType = new Dictionary<int, IReadOnlyList<RequestListPartition>>();
|
||||||
|
foreach (var rt in requestTypes)
|
||||||
|
archivedByType[rt.Id] = await partitionRegistry.GetArchivedAsync(rt, cancellationToken);
|
||||||
|
|
||||||
using var gate = new SemaphoreSlim(MaxParallelTypes);
|
using var gate = new SemaphoreSlim(MaxParallelTypes);
|
||||||
var results = await Task.WhenAll(requestTypes.Select(async rt =>
|
var results = await Task.WhenAll(requestTypes.Select(async rt =>
|
||||||
{
|
{
|
||||||
await gate.WaitAsync(cancellationToken);
|
await gate.WaitAsync(cancellationToken);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await FindForTypeSafeAsync(rt, statusFilter, email, cancellationToken);
|
return await FindForTypeSafeAsync(rt, archivedByType[rt.Id], statusFilter, email, cancellationToken);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -170,11 +178,11 @@ public sealed class RequestManageService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IReadOnlyList<UserApprovalRowDto>> FindForTypeSafeAsync(
|
private async Task<IReadOnlyList<UserApprovalRowDto>> FindForTypeSafeAsync(
|
||||||
RequestType requestType, string statusFilter, string approverEmail, CancellationToken cancellationToken)
|
RequestType requestType, IReadOnlyList<RequestListPartition> archived, string statusFilter, string approverEmail, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await FindForTypeAsync(requestType, statusFilter, approverEmail, cancellationToken);
|
return await FindForTypeAsync(requestType, archived, statusFilter, approverEmail, cancellationToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (ex is not OperationCanceledException)
|
catch (Exception ex) when (ex is not OperationCanceledException)
|
||||||
{
|
{
|
||||||
@@ -186,10 +194,9 @@ public sealed class RequestManageService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IReadOnlyList<UserApprovalRowDto>> FindForTypeAsync(
|
private async Task<IReadOnlyList<UserApprovalRowDto>> FindForTypeAsync(
|
||||||
RequestType requestType, string statusFilter, string approverEmail, CancellationToken cancellationToken)
|
RequestType requestType, IReadOnlyList<RequestListPartition> archived, string statusFilter, string approverEmail, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var siteUrl = requestType.SiteUrl!;
|
var siteUrl = requestType.SiteUrl!;
|
||||||
var archived = await partitionRegistry.GetArchivedAsync(requestType, cancellationToken);
|
|
||||||
var current = await partitionRegistry.BuildCurrentAsync(requestType, archived, cancellationToken);
|
var current = await partitionRegistry.BuildCurrentAsync(requestType, archived, cancellationToken);
|
||||||
|
|
||||||
var partitions = archived
|
var partitions = archived
|
||||||
|
|||||||
Reference in New Issue
Block a user