feat(api, core, dal, domain): В таблицу Tasks добавлено поле процент выполнения, так же добавлено это поле в response - статус формирования отчета. Создан интерфейс для отслеживания прогресса IProgressAsync. Из сервиса WorkloadService исключен ITaskManagementService.

This commit is contained in:
Mikhail Trubnikov
2026-05-20 14:26:25 +10:00
parent 8f61bbb73e
commit 68808e761b
17 changed files with 4160 additions and 41 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,57 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PARR.DAL.Migrations
{
/// <inheritdoc />
public partial class tblTaskItemAddProgressPercent : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "ProgressPercent",
schema: "task",
table: "Tasks",
type: "integer",
nullable: true,
comment: "Процент выполнения задачи");
migrationBuilder.InsertData(
table: "ParrComponents",
columns: new[] { "Id", "Description", "Name" },
values: new object[] { 14, "Генератор кэша отчетов workload", "WorkloadBuilder" });
migrationBuilder.UpdateData(
schema: "task",
table: "Types",
keyColumn: "Code",
keyValue: 0,
column: "MaxExecutionTimeMinutes",
value: 90);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "ParrComponents",
keyColumn: "Id",
keyValue: 14);
migrationBuilder.DropColumn(
name: "ProgressPercent",
schema: "task",
table: "Tasks");
migrationBuilder.UpdateData(
schema: "task",
table: "Types",
keyColumn: "Code",
keyValue: 0,
column: "MaxExecutionTimeMinutes",
value: 60);
}
}
}

View File

@@ -17,7 +17,7 @@ namespace PARR.DAL.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.20")
.HasAnnotation("ProductVersion", "9.0.16")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@@ -754,6 +754,12 @@ namespace PARR.DAL.Migrations
Id = 13,
Description = "Генератор шаблонов",
Name = "TemplateTaskGenerator"
},
new
{
Id = 14,
Description = "Генератор кэша отчетов workload",
Name = "WorkloadBuilder"
});
});
@@ -2406,6 +2412,10 @@ namespace PARR.DAL.Migrations
b.Property<DateTimeOffset?>("ProcessedAt")
.HasColumnType("timestamp with time zone");
b.Property<int?>("ProgressPercent")
.HasColumnType("integer")
.HasComment("Процент выполнения задачи");
b.Property<int>("RetryCount")
.HasColumnType("integer");
@@ -2512,7 +2522,7 @@ namespace PARR.DAL.Migrations
Code = 0,
Description = "Формирование данных для отчетности - Загруженность",
IsSingleton = true,
MaxExecutionTimeMinutes = 60,
MaxExecutionTimeMinutes = 90,
MaxRetries = 2,
Name = "Workload",
RetentionDays = 90

View File

@@ -15,24 +15,45 @@ namespace PARR.DAL.Repositories.TaskRepositories
public async Task<int> TaskCaptureAsync(Guid taskId)
{
//var affectedRows = await EntityContext.Database.ExecuteSqlInterpolatedAsync($@"
// UPDATE ""{DatabaseSchemas.Task}"".""Tasks""
// SET ""{nameof(TaskItem.StatusCode)}""={(int)TaskItemStatusEnum.Processing},
// ""{nameof(TaskItem.DateModified)}""={DateTimeOffset.UtcNow}
// WHERE ""{nameof(TaskItem.Id)}""={taskId}
// AND ""{nameof(TaskItem.StatusCode)}""={(int)TaskItemStatusEnum.Pending}
//");
//var sql = $@"
// UPDATE ""{DatabaseSchemas.Task}"".""Tasks""
// SET ""{nameof(TaskItem.StatusCode)}"" = {(int)TaskItemStatusEnum.Processing},
// ""{nameof(TaskItem.DateModified)}"" = {{0}}
// WHERE ""{nameof(TaskItem.Id)}"" = {{1}}
// AND ""{nameof(TaskItem.StatusCode)}"" = {(int)TaskItemStatusEnum.Pending}";
var sql = $@"
UPDATE ""{DatabaseSchemas.Task}"".""Tasks""
SET ""{nameof(TaskItem.StatusCode)}"" = {(int)TaskItemStatusEnum.Processing},
""{nameof(TaskItem.DateModified)}"" = {{0}}
WHERE ""{nameof(TaskItem.Id)}"" = {{1}}
AND ""{nameof(TaskItem.StatusCode)}"" = {(int)TaskItemStatusEnum.Pending}";
//var affectedRows = await EntityContext.Database.ExecuteSqlRawAsync(sql, DateTimeOffset.UtcNow, taskId);
var affectedRows = await EntityContext.Database.ExecuteSqlRawAsync(sql, DateTimeOffset.UtcNow, taskId);
//return affectedRows;
return affectedRows;
return await EntityContext.Tasks.Where(t => t.Id == taskId && t.StatusCode == TaskItemStatusEnum.Pending)
.ExecuteUpdateAsync(t=>t
.SetProperty(p=>p.StatusCode, TaskItemStatusEnum.Processing)
.SetProperty(p => p.DateModified, DateTimeOffset.UtcNow)
);
}
public async Task<int> UpdateProgressAsync(Guid taskId, int percent)
{
// Валидация на уровне БД
if (percent < 0)
percent = 0;
if (percent > 100)
percent = 100;
//return await EntityContext.Database.ExecuteSqlInterpolatedAsync($@"
// UPDATE ""{DatabaseSchemas.Task}"".""Tasks""
// SET ""{nameof(TaskItem.ProgressPercent)}"" = {percent},
// ""{nameof(TaskItem.DateModified)}"" = {DateTimeOffset.UtcNow}
// WHERE ""{nameof(TaskItem.Id)}"" = {taskId}");
// Атомарное обновление
return await EntityContext.Tasks.Where(t => t.Id == taskId).ExecuteUpdateAsync(t => t
.SetProperty(x => x.ProgressPercent, percent)
//.SetProperty(x => x.DateModified, DateTimeOffset.UtcNow)
);
}
}