Merge branch 'template-rename-pending' into dev
# Conflicts: # PARR.DAL/Repositories/TemplateRepository.cs
This commit is contained in:
@@ -1,40 +1,34 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using PARR.API.Contracts.V1;
|
using PARR.API.Contracts.V1;
|
||||||
using PARR.API.Contracts.V1.Requests;
|
using PARR.API.Contracts.V1.Requests;
|
||||||
using PARR.API.Contracts.V1.Responses;
|
using PARR.API.Contracts.V1.Responses;
|
||||||
using PARR.API.Contracts.V1.Responses.Base;
|
using PARR.API.Contracts.V1.Responses.Base;
|
||||||
using PARR.API.Controllers.V1.Base;
|
using PARR.API.Controllers.V1.Base;
|
||||||
using PARR.API.Services.Interfaces;
|
using PARR.API.Services.Interfaces;
|
||||||
using PARR.Core.Repositories.Interfaces;
|
using PARR.Core.Services.RobotTaskRobotStatus.Interfaces;
|
||||||
using PARR.Domain.Common.Roles;
|
using PARR.Domain.Common.Roles;
|
||||||
using PARR.Domain.Entities;
|
using PARR.Domain.DTOs.RobotTaskRobotStatus;
|
||||||
using PARR.Domain.Entities.RobotEntities;
|
|
||||||
using PARR.Domain.Enums;
|
|
||||||
|
|
||||||
namespace PARR.API.Controllers.V1
|
namespace PARR.API.Controllers.V1
|
||||||
{
|
{
|
||||||
[Authorize(Roles = ParrRoles.EsppRobot.RoleOrAdmin)]
|
[Authorize(Roles = ParrRoles.EsppRobot.RoleOrAdmin)]
|
||||||
public class RobotTaskRobotStatusController : BaseApiController
|
public class RobotTaskRobotStatusController : BaseApiController
|
||||||
{
|
{
|
||||||
private readonly IRobotConfigurationRepository robotConfigurationService;
|
private readonly IMapper _mapper;
|
||||||
private readonly IRobotHistoryRepository robotHistoryService;
|
private readonly IClientService _clientService;
|
||||||
private readonly IMapper mapper;
|
private readonly IRobotTaskRobotStatusService _robotTaskRobotStatusService;
|
||||||
private readonly IClientService clientService;
|
|
||||||
|
|
||||||
public RobotTaskRobotStatusController(
|
public RobotTaskRobotStatusController(
|
||||||
IRobotConfigurationRepository robotConfigurationService,
|
|
||||||
IRobotHistoryRepository robotHistoryService,
|
|
||||||
IMapper mapper,
|
IMapper mapper,
|
||||||
IClientService clientService
|
IClientService clientService,
|
||||||
|
IRobotTaskRobotStatusService robotTaskRobotStatusService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.robotConfigurationService = robotConfigurationService;
|
_mapper = mapper;
|
||||||
this.robotHistoryService = robotHistoryService;
|
_clientService = clientService;
|
||||||
this.mapper = mapper;
|
_robotTaskRobotStatusService = robotTaskRobotStatusService;
|
||||||
this.clientService = clientService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -46,47 +40,58 @@ namespace PARR.API.Controllers.V1
|
|||||||
[HttpPut(ApiRoutes.RobotTaskRobotStatus.ChangeRobotStatus)]
|
[HttpPut(ApiRoutes.RobotTaskRobotStatus.ChangeRobotStatus)]
|
||||||
public async Task<IActionResult> ChangeStatus([FromRoute] Guid taskId, [FromBody] RobotTaskChangeRobotStatusRequest request)
|
public async Task<IActionResult> ChangeStatus([FromRoute] Guid taskId, [FromBody] RobotTaskChangeRobotStatusRequest request)
|
||||||
{
|
{
|
||||||
var config = await robotConfigurationService.Get()
|
#region Old
|
||||||
.FirstOrDefaultAsync(t => t.Id == taskId);
|
|
||||||
|
|
||||||
if (config == null)
|
//var config = await _robotConfigurationRepository.Get()
|
||||||
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Не найдено задание с id: {taskId}" } }));
|
// .FirstOrDefaultAsync(t => t.Id == taskId);
|
||||||
|
|
||||||
//изменение статуса робота
|
//if (config == null)
|
||||||
robotConfigurationService.ChangeRobotStatus(request.RobotStatusCode, config);
|
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Не найдено задание с id: {taskId}" } }));
|
||||||
|
|
||||||
//если успех, изменяем статус задания на успех
|
////изменение статуса робота
|
||||||
if (request.RobotStatusCode == RobotStatusEnum.Complete)
|
//_robotConfigurationRepository.ChangeRobotStatus(request.RobotStatusCode, config);
|
||||||
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Ok, config);
|
|
||||||
|
|
||||||
if (!await robotConfigurationService.CommitAsync())
|
////если успех, изменяем статус задания на успех
|
||||||
return BadRequest("Ошибка при изменении статуса работы робота.");
|
//if (request.RobotStatusCode == RobotStatusEnum.Complete)
|
||||||
|
// _robotConfigurationRepository.ChangeTaskStatus(TaskStatusEnum.Ok, config);
|
||||||
|
|
||||||
//записываем в лог робота
|
//if (!await _robotConfigurationRepository.CommitAsync())
|
||||||
if (request.RobotStatusCode == RobotStatusEnum.InProgress || request.RobotStatusCode == RobotStatusEnum.Complete)
|
// return BadRequest("Ошибка при изменении статуса работы робота.");
|
||||||
{
|
|
||||||
var historyLevel = request.RobotStatusCode == RobotStatusEnum.InProgress ? RobotHistoryLevelEnum.Start : RobotHistoryLevelEnum.Complete;
|
|
||||||
|
|
||||||
var history = new RobotHistory
|
////записываем в лог робота
|
||||||
{
|
//if (request.RobotStatusCode == RobotStatusEnum.InProgress || request.RobotStatusCode == RobotStatusEnum.Complete)
|
||||||
Id = Guid.NewGuid(),
|
//{
|
||||||
HistoryLevel = (int)historyLevel,
|
// var historyLevel = request.RobotStatusCode == RobotStatusEnum.InProgress ? RobotHistoryLevelEnum.Start : RobotHistoryLevelEnum.Complete;
|
||||||
TaskStatusCode = config.TaskStatusCode,
|
|
||||||
RobotConfigurationId = config.Id,
|
|
||||||
RobotIp = clientService.GetClientIp()?.ToString(),
|
|
||||||
RobotId = request.RobotId
|
|
||||||
};
|
|
||||||
await robotHistoryService.CreateAsync(history);
|
|
||||||
await robotHistoryService.CommitAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
var configToResponse = await robotConfigurationService.Get()
|
// var history = new RobotHistory
|
||||||
.Include(t => t.Robot)
|
// {
|
||||||
.Include(t => t.TaskStatus)
|
// Id = Guid.NewGuid(),
|
||||||
.Include(t => t.RobotStatus)
|
// HistoryLevel = (int)historyLevel,
|
||||||
.FirstOrDefaultAsync(t => t.Id == taskId);
|
// TaskStatusCode = config.TaskStatusCode,
|
||||||
|
// RobotConfigurationId = config.Id,
|
||||||
|
// RobotIp = _clientService.GetClientIp()?.ToString(),
|
||||||
|
// RobotId = request.RobotId
|
||||||
|
// };
|
||||||
|
// await _robotHistoryRepository.CreateAsync(history);
|
||||||
|
// await _robotHistoryRepository.CommitAsync();
|
||||||
|
//}
|
||||||
|
|
||||||
var response = mapper.Map<RobotConfigurationResponse>(configToResponse);
|
//var configToResponse = await _robotConfigurationRepository.Get()
|
||||||
|
// .Include(t => t.Robot)
|
||||||
|
// .Include(t => t.TaskStatus)
|
||||||
|
// .Include(t => t.RobotStatus)
|
||||||
|
// .FirstOrDefaultAsync(t => t.Id == taskId);
|
||||||
|
|
||||||
|
//var response = _mapper.Map<RobotConfigurationResponse>(configToResponse);
|
||||||
|
|
||||||
|
//return Ok(new Response<RobotConfigurationResponse>(response, true));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
var changeRequest = new ChangeRobotStatus(taskId, request.RobotStatusCode, request.RobotId, _clientService.GetClientIp()?.ToString());
|
||||||
|
var result = await _robotTaskRobotStatusService.ChangeStatusAsync(changeRequest);
|
||||||
|
|
||||||
|
var response = _mapper.Map<RobotConfigurationResponse>(result);
|
||||||
|
|
||||||
return Ok(new Response<RobotConfigurationResponse>(response, true));
|
return Ok(new Response<RobotConfigurationResponse>(response, true));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ using PARR.Domain.DTOs.Matching;
|
|||||||
using PARR.Domain.DTOs.RobotMetrics;
|
using PARR.Domain.DTOs.RobotMetrics;
|
||||||
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||||
using PARR.Domain.DTOs.RobotTask;
|
using PARR.Domain.DTOs.RobotTask;
|
||||||
|
using PARR.Domain.DTOs.RobotTaskRobotStatus;
|
||||||
|
using PARR.Domain.DTOs.Shared;
|
||||||
using PARR.Domain.DTOs.Shortcode;
|
using PARR.Domain.DTOs.Shortcode;
|
||||||
using PARR.Domain.DTOs.TaskDTO;
|
using PARR.Domain.DTOs.TaskDTO;
|
||||||
using PARR.Domain.DTOs.User;
|
using PARR.Domain.DTOs.User;
|
||||||
@@ -258,10 +260,17 @@ namespace PARR.API.MappingProfiles
|
|||||||
|
|
||||||
CreateMap<PARR.Domain.Entities.RobotEntities.TaskStatus, TaskStatusResponse>();
|
CreateMap<PARR.Domain.Entities.RobotEntities.TaskStatus, TaskStatusResponse>();
|
||||||
|
|
||||||
CreateMap<RobotConfiguration, RobotConfigurationResponse>()
|
//CreateMap<RobotConfiguration, RobotConfigurationResponse>()
|
||||||
.ForMember(d => d.Robot, o => o.MapFrom(s => s.Robot))
|
// .ForMember(d => d.Robot, o => o.MapFrom(s => s.Robot))
|
||||||
.ForMember(d => d.TaskStatus, o => o.MapFrom(s => s.TaskStatus))
|
// .ForMember(d => d.TaskStatus, o => o.MapFrom(s => s.TaskStatus))
|
||||||
.ForMember(d => d.RobotStatus, o => o.MapFrom(s => s.RobotStatus));
|
// .ForMember(d => d.RobotStatus, o => o.MapFrom(s => s.RobotStatus));
|
||||||
|
|
||||||
|
CreateMap<RobotResult, RobotResponse>();
|
||||||
|
CreateMap<RobotTaskStatusResult, TaskStatusResponse>();
|
||||||
|
CreateMap<RobotStatusResult, RobotStatusResponse>();
|
||||||
|
|
||||||
|
CreateMap<RobotConfigurationResult, RobotConfigurationResponse>();
|
||||||
|
|
||||||
// === RobotConfiguration ===
|
// === RobotConfiguration ===
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning",
|
||||||
|
"Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "None"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Serilog": {
|
"Serilog": {
|
||||||
@@ -14,7 +15,8 @@
|
|||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Override": {
|
"Override": {
|
||||||
"Microsoft": "Warning",
|
"Microsoft": "Warning",
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
"Microsoft.Hosting.Lifetime": "Information",
|
||||||
|
"Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "Fatal"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -111,7 +113,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"RabbitMq": {
|
"RabbitMq": {
|
||||||
"ThresholdConnections": 33
|
"ThresholdConnections": 32
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CommonSettings": {
|
"CommonSettings": {
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ using PARR.Core.Services.RobotMetrics;
|
|||||||
using PARR.Core.Services.RobotSnapshotServices;
|
using PARR.Core.Services.RobotSnapshotServices;
|
||||||
using PARR.Core.Services.RobotTask.Implementations;
|
using PARR.Core.Services.RobotTask.Implementations;
|
||||||
using PARR.Core.Services.RobotTask.Interfaces;
|
using PARR.Core.Services.RobotTask.Interfaces;
|
||||||
|
using PARR.Core.Services.RobotTaskRobotStatus.Implemetations;
|
||||||
|
using PARR.Core.Services.RobotTaskRobotStatus.Interfaces;
|
||||||
using PARR.Core.Services.Shortcodes;
|
using PARR.Core.Services.Shortcodes;
|
||||||
using PARR.Core.Services.Shortcodes.Handlers;
|
using PARR.Core.Services.Shortcodes.Handlers;
|
||||||
using PARR.Core.Services.Snapshots.Implementations;
|
using PARR.Core.Services.Snapshots.Implementations;
|
||||||
@@ -111,6 +113,7 @@ namespace PARR.Core
|
|||||||
|
|
||||||
services.AddScoped<IRobotTaskService, RobotTaskService>();
|
services.AddScoped<IRobotTaskService, RobotTaskService>();
|
||||||
services.AddScoped<IRobotSnapshotService, RobotSnapshotService>();
|
services.AddScoped<IRobotSnapshotService, RobotSnapshotService>();
|
||||||
|
services.AddScoped<IRobotTaskRobotStatusService, RobotTaskRobotStatusService>();
|
||||||
|
|
||||||
services.AddScoped<IUnitService, UnitService>();
|
services.AddScoped<IUnitService, UnitService>();
|
||||||
services.AddScoped<UnitCacheService>();
|
services.AddScoped<UnitCacheService>();
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using PARR.Domain.DTOs.RobotTaskRobotStatus;
|
||||||
|
using PARR.Domain.Entities;
|
||||||
|
|
||||||
|
namespace PARR.Core.Infrastructure.Mapping.RobotTaskRobotStatus
|
||||||
|
{
|
||||||
|
internal class RobotConfigurationResultMappingProfile : Profile
|
||||||
|
{
|
||||||
|
public RobotConfigurationResultMappingProfile()
|
||||||
|
{
|
||||||
|
CreateMap<RobotConfiguration, RobotConfigurationResult>()
|
||||||
|
.ForMember(d => d.Robot, o => o.MapFrom(s => s.Robot))
|
||||||
|
.ForMember(d => d.TaskStatus, o => o.MapFrom(s => s.TaskStatus))
|
||||||
|
.ForMember(d => d.RobotStatus, o => o.MapFrom(s => s.RobotStatus));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using PARR.Domain.DTOs.Shared;
|
||||||
|
using PARR.Domain.Entities.RobotEntities;
|
||||||
|
|
||||||
|
namespace PARR.Core.Infrastructure.Mapping.Shared
|
||||||
|
{
|
||||||
|
public class RobotResultMappingProfile : Profile
|
||||||
|
{
|
||||||
|
public RobotResultMappingProfile()
|
||||||
|
{
|
||||||
|
CreateMap<Robot, RobotResult>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using PARR.Domain.DTOs.Shared;
|
||||||
|
using PARR.Domain.Entities.RobotEntities;
|
||||||
|
|
||||||
|
namespace PARR.Core.Infrastructure.Mapping.Shared
|
||||||
|
{
|
||||||
|
public class RobotStatusResultMappingProfile : Profile
|
||||||
|
{
|
||||||
|
public RobotStatusResultMappingProfile()
|
||||||
|
{
|
||||||
|
CreateMap<RobotStatus, RobotStatusResult>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using PARR.Domain.DTOs.Shared;
|
||||||
|
|
||||||
|
namespace PARR.Core.Infrastructure.Mapping.Shared
|
||||||
|
{
|
||||||
|
public class RobotTaskStatusResultMappingProfile : Profile
|
||||||
|
{
|
||||||
|
public RobotTaskStatusResultMappingProfile()
|
||||||
|
{
|
||||||
|
CreateMap<PARR.Domain.Entities.RobotEntities.TaskStatus, RobotTaskStatusResult>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,5 +49,11 @@ namespace PARR.Core.Repositories.Interfaces
|
|||||||
/// <param name="id"></param>
|
/// <param name="id"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> SetInProgressStatusAsync(Guid id);
|
Task<bool> SetInProgressStatusAsync(Guid id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Установить статус робота - Ошибка, и поставить максимальное значение попыток
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration"></param>
|
||||||
|
void SetErrorRobotStatusAndMaxAttempts(RobotConfiguration configuration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using PARR.Domain.Entities.TemplateEntities;
|
||||||
|
|
||||||
|
namespace PARR.Core.Repositories.Interfaces.TemplateRepositories
|
||||||
|
{
|
||||||
|
public interface ITemplateRenamePendingRepository
|
||||||
|
{
|
||||||
|
Task<bool> CreateAsync(TemplateRenamePending obj);
|
||||||
|
IQueryable<TemplateRenamePending> Get();
|
||||||
|
void Remove(TemplateRenamePending obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,10 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using PARR.BLL.Helpers;
|
using PARR.BLL.Helpers;
|
||||||
using PARR.Core.Repositories.Interfaces;
|
using PARR.Core.Repositories.Interfaces;
|
||||||
|
using PARR.Core.Repositories.Interfaces.TemplateRepositories;
|
||||||
using PARR.Core.Services.NextRunServices;
|
using PARR.Core.Services.NextRunServices;
|
||||||
using PARR.Core.Services.RobotTask.Interfaces;
|
using PARR.Core.Services.RobotTask.Interfaces;
|
||||||
|
using PARR.Core.Services.RobotTask.Models;
|
||||||
using PARR.Core.Services.Shortcodes;
|
using PARR.Core.Services.Shortcodes;
|
||||||
using PARR.Domain.DTOs.RobotTask;
|
using PARR.Domain.DTOs.RobotTask;
|
||||||
using PARR.Domain.Entities;
|
using PARR.Domain.Entities;
|
||||||
@@ -20,16 +22,18 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Количество заданий которые рассматриваем для взятия в работу.
|
/// Количество заданий которые рассматриваем для взятия в работу.
|
||||||
|
/// Рекомендованное значение, кол-во роботов * 3
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly int TakeTasks = 10;
|
private readonly int TakeTasks = 15 * 3;
|
||||||
|
|
||||||
private readonly ILogger<RobotTaskService> logger;
|
private readonly ILogger<RobotTaskService> _logger;
|
||||||
private readonly IRobotConfigurationRepository robotConfigurationRepository;
|
private readonly IRobotConfigurationRepository _robotConfigurationRepository;
|
||||||
private readonly SettingsFromDb settingsFromDb;
|
private readonly SettingsFromDb _settingsFromDb;
|
||||||
private readonly IRobotHistoryRepository robotHistoryRepository;
|
private readonly IRobotHistoryRepository _robotHistoryRepository;
|
||||||
private readonly IMapper mapper;
|
private readonly IMapper _mapper;
|
||||||
private readonly IShortcodesService shortcodesService;
|
private readonly IShortcodesService _shortcodesService;
|
||||||
private readonly INextRunService nextRunService;
|
private readonly INextRunService _nextRunService;
|
||||||
|
private readonly ITemplateRenamePendingRepository _templateRenamePendingRepository;
|
||||||
|
|
||||||
public RobotTaskService(
|
public RobotTaskService(
|
||||||
ILogger<RobotTaskService> logger,
|
ILogger<RobotTaskService> logger,
|
||||||
@@ -38,16 +42,18 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
IRobotHistoryRepository robotHistoryRepository,
|
IRobotHistoryRepository robotHistoryRepository,
|
||||||
IMapper mapper,
|
IMapper mapper,
|
||||||
IShortcodesService shortcodesService,
|
IShortcodesService shortcodesService,
|
||||||
INextRunService nextRunService
|
INextRunService nextRunService,
|
||||||
|
ITemplateRenamePendingRepository templateRenamePendingRepository
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
_logger = logger;
|
||||||
this.robotConfigurationRepository = robotConfigurationRepository;
|
_robotConfigurationRepository = robotConfigurationRepository;
|
||||||
this.settingsFromDb = settingsFromDb;
|
_settingsFromDb = settingsFromDb;
|
||||||
this.robotHistoryRepository = robotHistoryRepository;
|
_robotHistoryRepository = robotHistoryRepository;
|
||||||
this.mapper = mapper;
|
_mapper = mapper;
|
||||||
this.shortcodesService = shortcodesService;
|
_shortcodesService = shortcodesService;
|
||||||
this.nextRunService = nextRunService;
|
_nextRunService = nextRunService;
|
||||||
|
_templateRenamePendingRepository = templateRenamePendingRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -55,19 +61,19 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
{
|
{
|
||||||
var templateTask = await GetTaskAsync(RobotsEnum.TemplateOrder, taskStatusCode, acquireTask, robotIp, robotId, TimeSpan.Zero);
|
var templateTask = await GetTaskAsync(RobotsEnum.TemplateOrder, taskStatusCode, acquireTask, robotIp, robotId, TimeSpan.Zero);
|
||||||
|
|
||||||
var task = mapper.Map<RobotTaskTemplate>(templateTask);
|
var task = _mapper.Map<RobotTaskTemplate>(templateTask);
|
||||||
|
|
||||||
task = task with { FullDescription = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(task.FullDescription, templateTask.Template!)) };
|
task = task with { FullDescription = NormalizeLineEndingsToCrlf(await _shortcodesService.ApplyShortcodesAsync(task.FullDescription, templateTask.Template!)) };
|
||||||
task = task with { ShortDescription = await shortcodesService.ApplyShortcodesAsync(task.ShortDescription, templateTask.Template!) };
|
task = task with { ShortDescription = await _shortcodesService.ApplyShortcodesAsync(task.ShortDescription, templateTask.Template!) };
|
||||||
task = task with { Solution = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(task.Solution, templateTask.Template!)) };
|
task = task with { Solution = NormalizeLineEndingsToCrlf(await _shortcodesService.ApplyShortcodesAsync(task.Solution, templateTask.Template!)) };
|
||||||
task = task with { TnkName = await shortcodesService.ApplyShortcodesAsync(task.TnkName, templateTask.Template!) };
|
task = task with { TnkName = await _shortcodesService.ApplyShortcodesAsync(task.TnkName, templateTask.Template!) };
|
||||||
task = task with { WorkName = await shortcodesService.ApplyShortcodesAsync(task.WorkName, templateTask.Template!) };
|
task = task with { WorkName = await _shortcodesService.ApplyShortcodesAsync(task.WorkName, templateTask.Template!) };
|
||||||
task = task with { WorkGroup = await shortcodesService.ApplyShortcodesAsync(task.WorkGroup, templateTask.Template!) };
|
task = task with { WorkGroup = await _shortcodesService.ApplyShortcodesAsync(task.WorkGroup, templateTask.Template!) };
|
||||||
task = task with { ResponseArea = await shortcodesService.ApplyShortcodesAsync(task.ResponseArea, templateTask.Template!) };
|
task = task with { ResponseArea = await _shortcodesService.ApplyShortcodesAsync(task.ResponseArea, templateTask.Template!) };
|
||||||
|
|
||||||
task = task with { ClosingCode = settingsFromDb.ClosingCode };
|
task = task with { ClosingCode = _settingsFromDb.ClosingCode };
|
||||||
task = task with { Initiator = settingsFromDb.Initiator };
|
task = task with { Initiator = _settingsFromDb.Initiator };
|
||||||
task = task with { Category = settingsFromDb.Category };
|
task = task with { Category = _settingsFromDb.Category };
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
@@ -82,22 +88,22 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
var resultUpdateNextRun = await UpdateNextRunAsync(scheduleTask, historyInitiator);
|
var resultUpdateNextRun = await UpdateNextRunAsync(scheduleTask, historyInitiator);
|
||||||
if (!resultUpdateNextRun)
|
if (!resultUpdateNextRun)
|
||||||
{
|
{
|
||||||
logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}", scheduleTask.TemplateId);
|
_logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}", scheduleTask.TemplateId);
|
||||||
throw new NextRunException($"Ошибка при расчете NextRun для templateId: {scheduleTask.TemplateId}");
|
throw new NextRunException($"Ошибка при расчете NextRun для templateId: {scheduleTask.TemplateId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var task = mapper.Map<RobotTaskSchedule>(scheduleTask);
|
var task = _mapper.Map<RobotTaskSchedule>(scheduleTask);
|
||||||
|
|
||||||
task = task with { Timezone = settingsFromDb.EsppScheduleTimezone };
|
task = task with { Timezone = _settingsFromDb.EsppScheduleTimezone };
|
||||||
task = task with { WorkGroup = await shortcodesService.ApplyShortcodesAsync(task.WorkGroup, scheduleTask.Template!) };
|
task = task with { WorkGroup = await _shortcodesService.ApplyShortcodesAsync(task.WorkGroup, scheduleTask.Template!) };
|
||||||
task = task with { ResponseArea = await shortcodesService.ApplyShortcodesAsync(task.ResponseArea, scheduleTask.Template!) };
|
task = task with { ResponseArea = await _shortcodesService.ApplyShortcodesAsync(task.ResponseArea, scheduleTask.Template!) };
|
||||||
|
|
||||||
//nextRun в часовой зоне УЗ Робота ЕСПП
|
//nextRun в часовой зоне УЗ Робота ЕСПП
|
||||||
var nextRunWithRobotTz = scheduleTask.Template!.NextRun.Add(nextRunService.GetEsppAccountOffset());
|
var nextRunWithRobotTz = scheduleTask.Template!.NextRun.Add(_nextRunService.GetEsppAccountOffset());
|
||||||
//на всякий случай еще раз проверяем, что дата не устарела и отправляем задание
|
//на всякий случай еще раз проверяем, что дата не устарела и отправляем задание
|
||||||
if (nextRunWithRobotTz < DateTimeOffset.UtcNow)
|
if (nextRunWithRobotTz < DateTimeOffset.UtcNow)
|
||||||
{
|
{
|
||||||
logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}, итоговое значение для робота, меньше чем сейчас {nextRunWithRobotTz}<{now}",
|
_logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}, итоговое значение для робота, меньше чем сейчас {nextRunWithRobotTz}<{now}",
|
||||||
task.TemplateId, nextRunWithRobotTz, DateTimeOffset.UtcNow);
|
task.TemplateId, nextRunWithRobotTz, DateTimeOffset.UtcNow);
|
||||||
throw new NextRunException($"Ошибка при расчете NextRun для templateId: {scheduleTask.TemplateId}");
|
throw new NextRunException($"Ошибка при расчете NextRun для templateId: {scheduleTask.TemplateId}");
|
||||||
}
|
}
|
||||||
@@ -105,7 +111,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
task = task with { NextStart = EsppScheduleHelpers.GetNextRun(nextRunWithRobotTz) };
|
task = task with { NextStart = EsppScheduleHelpers.GetNextRun(nextRunWithRobotTz) };
|
||||||
task = task with { GenerationTime = EsppScheduleHelpers.GetGenerationTime(nextRunWithRobotTz) };
|
task = task with { GenerationTime = EsppScheduleHelpers.GetGenerationTime(nextRunWithRobotTz) };
|
||||||
|
|
||||||
task = task with { RepeatRange = settingsFromDb.ScheduleRepeatRange };
|
task = task with { RepeatRange = _settingsFromDb.ScheduleRepeatRange };
|
||||||
task = task with { };
|
task = task with { };
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
@@ -125,7 +131,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
private async Task<RobotConfiguration> GetTaskAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId, TimeSpan scheduleCooldownDuration)
|
private async Task<RobotConfiguration> GetTaskAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId, TimeSpan scheduleCooldownDuration)
|
||||||
{
|
{
|
||||||
// 1. Ищем все задания с превышенным кол-вом попыток и просроченным временем, ставим им статус ошибки
|
// 1. Ищем все задания с превышенным кол-вом попыток и просроченным временем, ставим им статус ошибки
|
||||||
await robotConfigurationRepository.MarkExpiredTasksAsFailedAsync(settingsFromDb.RobotAttemptsNumber, settingsFromDb.RobotWaitTime);
|
await _robotConfigurationRepository.MarkExpiredTasksAsFailedAsync(_settingsFromDb.RobotAttemptsNumber, _settingsFromDb.RobotWaitTime);
|
||||||
|
|
||||||
|
|
||||||
// 2. Ищем доступные задания
|
// 2. Ищем доступные задания
|
||||||
@@ -148,7 +154,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
{
|
{
|
||||||
// Берем первую задачу из списка доступных
|
// Берем первую задачу из списка доступных
|
||||||
acquiredTaskId = availableTasks.First();
|
acquiredTaskId = availableTasks.First();
|
||||||
logger.LogDebug("Задача не требует захвата, взята первая из доступных: {TaskId}", acquiredTaskId);
|
_logger.LogDebug("Задача не требует захвата, взята первая из доступных: {TaskId}", acquiredTaskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -168,20 +174,14 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task<List<Guid>> GetAvailableTasksAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, TimeSpan scheduleCooldownDuration)
|
private async Task<List<Guid>> GetAvailableTasksAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, TimeSpan scheduleCooldownDuration)
|
||||||
{
|
{
|
||||||
var query = robotConfigurationRepository.Get()
|
var query = _robotConfigurationRepository.Get()
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(t => t.RobotCode == (int)robotCode/* && t.TaskStatusCode == (int)taskStatusCode*/);
|
.Where(t => t.RobotCode == (int)robotCode);
|
||||||
|
|
||||||
// Если это задание для робота расписаний
|
// Если это задание для робота расписаний
|
||||||
if (robotCode == RobotsEnum.ScheduleOrder)
|
if (robotCode == RobotsEnum.ScheduleOrder)
|
||||||
{
|
{
|
||||||
// Выбираем только записи с созданными шаблонами (у которых статус 30), а только потом ищем у них расписания
|
// Выбираем только записи с созданными шаблонами (у которых статус 30), а только потом ищем у них расписания
|
||||||
#region Старый не оптимизированный запрос
|
|
||||||
//var createdTemplates = robotConfigurationRepository.Get()
|
|
||||||
// .Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder && t.TaskStatusCode == (int)TaskStatusEnum.Ok)
|
|
||||||
// .Select(t => t.TemplateId);
|
|
||||||
//query = query.Where(t => createdTemplates.Contains(t.TemplateId));
|
|
||||||
#endregion
|
|
||||||
query = query.Where(t => t.Template!.RobotConfigurations.Any(x => x.RobotCode == (int)RobotsEnum.TemplateOrder && x.TaskStatusCode == (int)TaskStatusEnum.Ok));
|
query = query.Where(t => t.Template!.RobotConfigurations.Any(x => x.RobotCode == (int)RobotsEnum.TemplateOrder && x.TaskStatusCode == (int)TaskStatusEnum.Ok));
|
||||||
|
|
||||||
|
|
||||||
@@ -200,20 +200,22 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
// Сортируем по nextRun, чтобы те, у кого nextRun ближе к текущей, выполнились скорее
|
// Сортируем по nextRun, чтобы те, у кого nextRun ближе к текущей, выполнились скорее
|
||||||
query = query.OrderBy(t => t.Template!.NextRun).ThenBy(t => t.Template!.IsActiveSchedule).ThenBy(t => t.Template!.IsActiveTemplate);
|
query = query.OrderBy(t => t.Template!.NextRun).ThenBy(t => t.Template!.IsActiveSchedule).ThenBy(t => t.Template!.IsActiveTemplate);
|
||||||
|
|
||||||
// Кандидаты заданий
|
// Кандидаты заданий, Id задания и имя шаблона
|
||||||
var tasks = new List<Guid>();
|
//var tasks = new List<Guid>();
|
||||||
|
var tasks = new List<RobotTaskDetails>();
|
||||||
|
|
||||||
// Ещем первые 10 заданий в статусе ОЖИДАНИЕ
|
// Ищем первые TakeTasks заданий в статусе ОЖИДАНИЕ
|
||||||
tasks = await query
|
tasks = await query
|
||||||
.Where(t =>
|
.Where(t =>
|
||||||
t.RobotStatusCode == (int)RobotStatusEnum.Wait
|
t.RobotStatusCode == (int)RobotStatusEnum.Wait
|
||||||
&& t.TaskStatusCode == (int)taskStatusCode
|
&& t.TaskStatusCode == (int)taskStatusCode
|
||||||
).Take(TakeTasks)
|
).Take(TakeTasks)
|
||||||
.Select(t => t.Id)
|
//.Select(t => t.Id)
|
||||||
|
.Select(t => new RobotTaskDetails(t.Id, t.Template!.Name, t.Template.NextRun))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
|
||||||
logger.LogDebug("Найдено заданий в статусе 'Ожидание' {Count} шт. Робот '{Robot}'", tasks.Count, robotCode.ToString());
|
_logger.LogDebug("Найдено заданий в статусе 'Ожидание' {Count} шт. Робот '{Robot}'", tasks.Count, robotCode.ToString());
|
||||||
|
|
||||||
if (tasks.Count == 0)
|
if (tasks.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -222,20 +224,209 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
// Далее проверяется `LastStatusUpdated`, что время последнего смены статуса не превышает допустимого(берется из настроек, поле `RobotWaitTime`)
|
// Далее проверяется `LastStatusUpdated`, что время последнего смены статуса не превышает допустимого(берется из настроек, поле `RobotWaitTime`)
|
||||||
// и что текущая попытка не больше разрешенной(берется из настроек, поле `RobotAttemptsNumber`) - если это так, берется эта запись.
|
// и что текущая попытка не больше разрешенной(берется из настроек, поле `RobotAttemptsNumber`) - если это так, берется эта запись.
|
||||||
|
|
||||||
var endDate = DateTimeOffset.UtcNow.Add(-settingsFromDb.RobotWaitTime);
|
var endDate = DateTimeOffset.UtcNow.Add(-_settingsFromDb.RobotWaitTime);
|
||||||
|
|
||||||
tasks = await query.Where(t => t.RobotStatusCode == (int)RobotStatusEnum.InProgress
|
tasks = await query.Where(t => t.RobotStatusCode == (int)RobotStatusEnum.InProgress
|
||||||
&& t.TaskStatusCode==(int)taskStatusCode
|
&& t.TaskStatusCode == (int)taskStatusCode
|
||||||
&& t.AttemptsNumber < settingsFromDb.RobotAttemptsNumber
|
&& t.AttemptsNumber < _settingsFromDb.RobotAttemptsNumber
|
||||||
&& t.LastRobotStatusUpdated < endDate)
|
&& t.LastRobotStatusUpdated < endDate)
|
||||||
.Take(TakeTasks)
|
.Take(TakeTasks)
|
||||||
.Select(t => t.Id)
|
//.Select(t => t.Id)
|
||||||
|
.Select(t => new RobotTaskDetails(t.Id, t.Template!.Name, t.Template.NextRun))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
logger.LogDebug("Найдено заданий в статусе 'В работе' {Count} шт. Робот '{Robot}'", tasks.Count, robotCode.ToString());
|
_logger.LogDebug("Найдено заданий в статусе 'В работе' {Count} шт. Робот '{Robot}'", tasks.Count, robotCode.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return tasks;
|
if (robotCode == RobotsEnum.TemplateOrder)
|
||||||
|
{
|
||||||
|
// Если запрашиваем шаблоны, смотрим корректируем список заданий в зависимости от статуса переименования.
|
||||||
|
// Это не относится к расписаниям, потому что у переименованных расписаний статус Updating, а оно не возьмется в работу, пока не обновится шаблон
|
||||||
|
tasks = await ReplaceTemplateTasksForRenameAsync(tasks, robotCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tasks.Select(t => t.TaskId).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Проверяет наличие шаблонов в процессе переименования и заменяет обычные задания на задания по переименованию.
|
||||||
|
/// Если связанный шаблон не переименован, и у него статус ошибки, целевому шаблону устанавливается статус ошибки.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tasks"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task<List<RobotTaskDetails>> ReplaceTemplateTasksForRenameAsync(List<RobotTaskDetails> tasks, RobotsEnum robotCode)
|
||||||
|
{
|
||||||
|
if (tasks.Count == 0 || robotCode != RobotsEnum.TemplateOrder)
|
||||||
|
return tasks;
|
||||||
|
|
||||||
|
|
||||||
|
// Ищем есть ли связанные шаблоны с таким имененм на переименование
|
||||||
|
var taskTemplateNames = tasks.Select(t => t.TemplateName).Distinct().ToList();
|
||||||
|
// Ищем записи в таблице переименований, где OldName совпадает с именами наших новых задач
|
||||||
|
var templatesToRename = await _templateRenamePendingRepository.Get().AsNoTracking()
|
||||||
|
.Where(t => taskTemplateNames.Contains(t.OldName))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
_logger.LogDebug("Найдено шаблонов в процессе переименования для текущих задач: {Count} шт.", templatesToRename.Count);
|
||||||
|
|
||||||
|
if (templatesToRename.Count == 0)
|
||||||
|
return tasks;
|
||||||
|
|
||||||
|
// Ищем конфигурации роботов для СТАРЫХ шаблонов (которые переименовываются) по ИД, смотрим, можем ли взять их в работу
|
||||||
|
var renameTemplateIds = templatesToRename.Select(t => t.TemplateId).ToList();
|
||||||
|
var renameTasks = await _robotConfigurationRepository.Get()
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(t => t.Template)
|
||||||
|
.Where(t =>
|
||||||
|
t.RobotCode == (int)robotCode
|
||||||
|
&& renameTemplateIds.Contains(t.TemplateId)
|
||||||
|
// Это может быть только обновление. Так как переименования для создаваемого шаблона быть не может
|
||||||
|
&& t.TaskStatusCode == (int)TaskStatusEnum.Updating
|
||||||
|
).ToListAsync();
|
||||||
|
|
||||||
|
// --- Блок обработки ошибок ---
|
||||||
|
|
||||||
|
// Если старый шаблон в ошибке и лимит попыток исчерпан, ставим ошибку и новому шаблону
|
||||||
|
var errorTasks = renameTasks
|
||||||
|
.Where(t =>
|
||||||
|
t.RobotStatusCode == (int)RobotStatusEnum.Error
|
||||||
|
&& t.AttemptsNumber >= _settingsFromDb.RobotAttemptsNumber
|
||||||
|
).ToList();
|
||||||
|
|
||||||
|
var tasksToSetErrorStatus = new List<Guid>();
|
||||||
|
if (errorTasks.Count > 0)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Найдено старых заданий на переименование с ошибками: {ErrorCount}. Ставим ошибку целевым (новым) заданиям.", errorTasks.Count);
|
||||||
|
|
||||||
|
var errorTemplateNames = errorTasks.Select(t => t.Template!.Name).ToHashSet();
|
||||||
|
// Берем целевые таски, находим в них задания которым надо поставить ошибку
|
||||||
|
tasksToSetErrorStatus = tasks
|
||||||
|
.Where(t => errorTemplateNames.Contains(t.TemplateName))
|
||||||
|
.Select(t => t.TaskId)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (tasksToSetErrorStatus.Count > 0)
|
||||||
|
{
|
||||||
|
// Устанавливаем ошибку целевым + пишем комментарий от робота + нажимаем комит
|
||||||
|
var logMessage = "[RobotTaskService] Установлен статус ошибки, так как не переименован связанный шаблон";
|
||||||
|
await SetErrorStatusAsync(tasksToSetErrorStatus, logMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Блок подмены задач ---
|
||||||
|
|
||||||
|
var endDate = DateTimeOffset.UtcNow.Add(-_settingsFromDb.RobotWaitTime);
|
||||||
|
|
||||||
|
// Фильтруем старые задачи, которые МОЖНО взять в работу. Смотрим статусы роботов, можно взять в работу, только если (RobotStatus == Wait) или (InpRogress но которые еще не просрочены)
|
||||||
|
var allowedRenameTasks = renameTasks.Where(t =>
|
||||||
|
t.RobotStatusCode == (int)RobotStatusEnum.Wait
|
||||||
|
|| (t.RobotStatusCode == (int)RobotStatusEnum.InProgress
|
||||||
|
&& t.AttemptsNumber < _settingsFromDb.RobotAttemptsNumber
|
||||||
|
&& t.LastRobotStatusUpdated < endDate)
|
||||||
|
).ToList();
|
||||||
|
|
||||||
|
// Словарь для поиска подменной задачи по имени шаблона.
|
||||||
|
// GroupBy + First на случай, если в бд есть дубликаты, но такого быть не может
|
||||||
|
var renameTasksToDictionary = allowedRenameTasks
|
||||||
|
.GroupBy(t => t.Template!.Name)
|
||||||
|
.ToDictionary(
|
||||||
|
t => t.Key,
|
||||||
|
t => new RobotTaskDetails(t.First().Id, t.First().Template!.Name, t.First().Template!.NextRun)
|
||||||
|
);
|
||||||
|
|
||||||
|
var errorTaskIdsSet = tasksToSetErrorStatus.ToHashSet();
|
||||||
|
|
||||||
|
// Создаем итоговый список
|
||||||
|
var finalTasks = new List<RobotTaskDetails>(tasks.Count);
|
||||||
|
int replacedCount = 0;
|
||||||
|
int errorCount = errorTaskIdsSet.Count;
|
||||||
|
|
||||||
|
// Проходим по ИСХОДНОМУ списку, чтобы сохранить его порядок сортировки
|
||||||
|
foreach (var task in tasks)
|
||||||
|
{
|
||||||
|
// Если задаче нужно поставить ошибку, просто пропускаем ее (она не попадет в итоговый список)
|
||||||
|
if (errorTaskIdsSet.Contains(task.TaskId))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если для этого имени шаблона есть разрешенная задача на переименование - вставляем ее на место текущей
|
||||||
|
if (renameTasksToDictionary.TryGetValue(task.TemplateName, out var renameTask))
|
||||||
|
{
|
||||||
|
finalTasks.Add(renameTask);
|
||||||
|
replacedCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Иначе оставляем исходную задачу на месте
|
||||||
|
finalTasks.Add(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Трансформация пула задач (Rename). Исходных: {OriginalCount}. Отклонено (Error): {ErrorCount}. " +
|
||||||
|
"Заменено на старые: {ReplacedCount}. Итого к выдаче: {FinalCount}",
|
||||||
|
tasks.Count, errorCount, replacedCount, finalTasks.Count
|
||||||
|
);
|
||||||
|
|
||||||
|
// Возвращаем без дополнительной сортировки по NextRun. Порядок сохранен начального списка
|
||||||
|
return finalTasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Установить статус задания - ошибка
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskIds"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task SetErrorStatusAsync(List<Guid> taskIds, string logMessage)
|
||||||
|
{
|
||||||
|
if (taskIds == null || taskIds.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var tasks = await _robotConfigurationRepository.Get()
|
||||||
|
.Include(t => t.Template)
|
||||||
|
.Where(t => taskIds.Contains(t.Id))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
if (tasks.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var task in tasks)
|
||||||
|
{
|
||||||
|
// Так как это целевой шаблон, то ставим ему сразу максимальное кол-во попыток и ошибку, чтоб больше он не выдавался в заданиях, пока не исправим связанный
|
||||||
|
// Устанавливаем статус ошибки
|
||||||
|
_robotConfigurationRepository.SetErrorRobotStatusAndMaxAttempts(task);
|
||||||
|
|
||||||
|
// Пишем в лог роботу
|
||||||
|
var history = new RobotHistory
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
HistoryLevel = (int)RobotStatusEnum.Error,
|
||||||
|
TaskStatusCode = task.TaskStatusCode,
|
||||||
|
RobotConfigurationId = task.Id,
|
||||||
|
RobotIp = null,
|
||||||
|
RobotId = ParrComponentsEnum.Api.ToString(),
|
||||||
|
RobotMessage = logMessage
|
||||||
|
};
|
||||||
|
|
||||||
|
await _robotHistoryRepository.CreateAsync(history);
|
||||||
|
|
||||||
|
_logger.LogInformation("Для целевого задания {TaskId} (шаблон '{TemplateName}') установлен статус ошибки, " +
|
||||||
|
"так как связанное задание со старым шаблоном не было успешно выполнено.",
|
||||||
|
task.Id, task.Template!.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await _robotHistoryRepository.CommitAsync())
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Установлен статус 'Ошибка', для заданий {TaskCount} шт.", tasks.Count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogError("Ошибка при установке статуса задания 'Ошибка', для заданий {TaskCount} шт. Транзакция отменена", tasks.Count);
|
||||||
|
throw new DbErrorException("Не удалось сохранить изменения статусов заданий при обработке переименования шаблона.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -248,12 +439,12 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
{
|
{
|
||||||
foreach (var taskId in tasks)
|
foreach (var taskId in tasks)
|
||||||
{
|
{
|
||||||
var isChangedStatus = await robotConfigurationRepository.SetInProgressStatusAsync(taskId);
|
var isChangedStatus = await _robotConfigurationRepository.SetInProgressStatusAsync(taskId);
|
||||||
if (isChangedStatus)
|
if (isChangedStatus)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Захвачена задача {TaskId}", taskId);
|
_logger.LogDebug("Захвачена задача {TaskId}", taskId);
|
||||||
|
|
||||||
var task = await robotConfigurationRepository.Get()
|
var task = await _robotConfigurationRepository.Get()
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.FirstAsync(t => t.Id == taskId);
|
.FirstAsync(t => t.Id == taskId);
|
||||||
|
|
||||||
@@ -268,18 +459,18 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
RobotId = robotId
|
RobotId = robotId
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!await robotHistoryRepository.CreateAsync(history) || !await robotHistoryRepository.CommitAsync())
|
if (!await _robotHistoryRepository.CreateAsync(history) || !await _robotHistoryRepository.CommitAsync())
|
||||||
throw new DbErrorException("Ошибка при добавлении истории робота, при взятии задания в работу.");
|
throw new DbErrorException("Ошибка при добавлении истории робота, при взятии задания в работу.");
|
||||||
|
|
||||||
return taskId;
|
return taskId;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.LogDebug("Не удалось захватить задачу {TaskId}", taskId);
|
_logger.LogDebug("Не удалось захватить задачу {TaskId}", taskId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.LogDebug("Не удалось захватить ни одну из доступных задач для робота");
|
_logger.LogDebug("Не удалось захватить ни одну из доступных задач для робота");
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -293,7 +484,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task<RobotConfiguration> GetTaskWithAllDataAsync(Guid taskId, RobotsEnum robotCode)
|
private async Task<RobotConfiguration> GetTaskWithAllDataAsync(Guid taskId, RobotsEnum robotCode)
|
||||||
{
|
{
|
||||||
IQueryable<RobotConfiguration> query = robotConfigurationRepository.Get()
|
IQueryable<RobotConfiguration> query = _robotConfigurationRepository.Get()
|
||||||
//.AsNoTracking() // нужно обязательно трекать, так как может измениться nextRun и его нужно будет сохранить
|
//.AsNoTracking() // нужно обязательно трекать, так как может измениться nextRun и его нужно будет сохранить
|
||||||
.AsSingleQuery()
|
.AsSingleQuery()
|
||||||
// Общие инклуды для шаблонов и расписаний
|
// Общие инклуды для шаблонов и расписаний
|
||||||
@@ -372,23 +563,23 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
var template = task.Template!;
|
var template = task.Template!;
|
||||||
|
|
||||||
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate);
|
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate);
|
||||||
var nextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);
|
var nextRun = await _nextRunService.GetNextRunForTemplateAsync(template.Id, false);
|
||||||
|
|
||||||
if (!nextRun.HasValue)
|
if (!nextRun.HasValue)
|
||||||
{
|
{
|
||||||
logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun=null, ошибка в расчетах.", template.Id);
|
_logger.LogError("При обновлении nextRun для шаблона {TemplateId}, расчитанный nextRun=null, ошибка в расчетах.", template.Id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextRun.Value < DateTimeOffset.UtcNow)
|
if (nextRun.Value < DateTimeOffset.UtcNow)
|
||||||
{
|
{
|
||||||
logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun<Now [{nextRun}<{now}], ошибка в расчетах.", template.Id, nextRun.Value, DateTimeOffset.UtcNow);
|
_logger.LogError("При обновлении nextRun для шаблона {TemplateId}, расчитанный nextRun<Now [{NextRun}<{Now}], ошибка в расчетах.", template.Id, nextRun.Value, DateTimeOffset.UtcNow);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextRun != template.NextRun)
|
if (nextRun != template.NextRun)
|
||||||
{
|
{
|
||||||
logger.LogDebug($"Для шаблона id {template.Id} обновляю nextRun, новое значение {nextRun}, старое значение {template.NextRun}");
|
_logger.LogDebug("Для шаблона {TemplateId} обновляю nextRun. Новое: {NewNextRun}, старое: {OldNextRun}", template.Id, nextRun, template.NextRun);
|
||||||
|
|
||||||
template.LastRun = template.NextRun;
|
template.LastRun = template.NextRun;
|
||||||
template.NextRun = nextRun.Value;
|
template.NextRun = nextRun.Value;
|
||||||
@@ -399,7 +590,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
? suffix
|
? suffix
|
||||||
: $"{historyInitiator.InitiatorComment}. {suffix}";
|
: $"{historyInitiator.InitiatorComment}. {suffix}";
|
||||||
|
|
||||||
if (!await robotConfigurationRepository.CommitAsync(historyInitiator))
|
if (!await _robotConfigurationRepository.CommitAsync(historyInitiator))
|
||||||
throw new DbErrorException("Ошибка при сохранении изменения NextRun");
|
throw new DbErrorException("Ошибка при сохранении изменения NextRun");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
PARR.Core/Services/RobotTask/Models/RobotTaskDetails.cs
Normal file
9
PARR.Core/Services/RobotTask/Models/RobotTaskDetails.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace PARR.Core.Services.RobotTask.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Модель задания для робота
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="TaskId"></param>
|
||||||
|
/// <param name="TemplateName"></param>
|
||||||
|
internal record RobotTaskDetails(Guid TaskId, string TemplateName, DateTimeOffset NextRun);
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PARR.Core.Repositories.Interfaces;
|
||||||
|
using PARR.Core.Repositories.Interfaces.TemplateRepositories;
|
||||||
|
using PARR.Core.Services.RobotTaskRobotStatus.Interfaces;
|
||||||
|
using PARR.Domain.DTOs.RobotTaskRobotStatus;
|
||||||
|
using PARR.Domain.Entities.RobotEntities;
|
||||||
|
using PARR.Domain.Enums;
|
||||||
|
using PARR.Domain.Exceptions;
|
||||||
|
|
||||||
|
namespace PARR.Core.Services.RobotTaskRobotStatus.Implemetations
|
||||||
|
{
|
||||||
|
internal class RobotTaskRobotStatusService : IRobotTaskRobotStatusService
|
||||||
|
{
|
||||||
|
private readonly ILogger<RobotTaskRobotStatusService> _logger;
|
||||||
|
private readonly IRobotConfigurationRepository _robotConfigurationRepository;
|
||||||
|
private readonly IRobotHistoryRepository _robotHistoryRepository;
|
||||||
|
private readonly ITemplateRenamePendingRepository _templateRenamePendingRepository;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public RobotTaskRobotStatusService(
|
||||||
|
ILogger<RobotTaskRobotStatusService> logger,
|
||||||
|
IRobotConfigurationRepository robotConfigurationRepository,
|
||||||
|
IRobotHistoryRepository robotHistoryRepository,
|
||||||
|
ITemplateRenamePendingRepository templateRenamePendingRepository,
|
||||||
|
IMapper mapper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_robotConfigurationRepository = robotConfigurationRepository;
|
||||||
|
_robotHistoryRepository = robotHistoryRepository;
|
||||||
|
_templateRenamePendingRepository = templateRenamePendingRepository;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<RobotConfigurationResult> ChangeStatusAsync(ChangeRobotStatus request)
|
||||||
|
{
|
||||||
|
var config = await _robotConfigurationRepository.Get()
|
||||||
|
.FirstOrDefaultAsync(t => t.Id == request.TaskId);
|
||||||
|
|
||||||
|
if (config == null)
|
||||||
|
throw new NotFoundException($"Не найдено задание с id: {request.TaskId}");
|
||||||
|
|
||||||
|
// изменение статуса робота
|
||||||
|
_robotConfigurationRepository.ChangeRobotStatus(request.RobotStatusCode, config);
|
||||||
|
|
||||||
|
// если успех, изменяем статус задания на успех
|
||||||
|
if (request.RobotStatusCode == RobotStatusEnum.Complete)
|
||||||
|
{
|
||||||
|
_robotConfigurationRepository.ChangeTaskStatus(TaskStatusEnum.Ok, config);
|
||||||
|
// Тут нужно посмотреть, если этот шаблон был на переименование, удалить у него старое название, так как он успешно переименовался
|
||||||
|
if (config.RobotCode == (int)RobotsEnum.TemplateOrder)
|
||||||
|
{
|
||||||
|
var renaming = await _templateRenamePendingRepository.Get().FirstOrDefaultAsync(t => t.TemplateId == config.TemplateId);
|
||||||
|
if (renaming != null)
|
||||||
|
{
|
||||||
|
// Удаляем
|
||||||
|
_templateRenamePendingRepository.Remove(renaming);
|
||||||
|
_logger.LogInformation("Шаблон {TemplateId} успешно переименован. Запись TemplateRenamePending удалена.", config.TemplateId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await _robotConfigurationRepository.CommitAsync())
|
||||||
|
throw new DbErrorException("Ошибка при сохранении в БД");
|
||||||
|
|
||||||
|
|
||||||
|
//записываем в лог робота
|
||||||
|
if (request.RobotStatusCode == RobotStatusEnum.InProgress || request.RobotStatusCode == RobotStatusEnum.Complete)
|
||||||
|
{
|
||||||
|
var historyLevel = request.RobotStatusCode == RobotStatusEnum.InProgress ? RobotHistoryLevelEnum.Start : RobotHistoryLevelEnum.Complete;
|
||||||
|
|
||||||
|
var history = new RobotHistory
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
HistoryLevel = (int)historyLevel,
|
||||||
|
TaskStatusCode = config.TaskStatusCode,
|
||||||
|
RobotConfigurationId = config.Id,
|
||||||
|
RobotIp = request.RobotIp,
|
||||||
|
RobotId = request.RobotId
|
||||||
|
};
|
||||||
|
await _robotHistoryRepository.CreateAsync(history);
|
||||||
|
await _robotHistoryRepository.CommitAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
var configToResponse = await _robotConfigurationRepository.Get()
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(t => t.Robot)
|
||||||
|
.Include(t => t.TaskStatus)
|
||||||
|
.Include(t => t.RobotStatus)
|
||||||
|
.FirstOrDefaultAsync(t => t.Id == request.TaskId);
|
||||||
|
|
||||||
|
return _mapper.Map<RobotConfigurationResult>(configToResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using PARR.Domain.DTOs.RobotTaskRobotStatus;
|
||||||
|
|
||||||
|
namespace PARR.Core.Services.RobotTaskRobotStatus.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Сервис по изменению статуса выполнения задания роботами
|
||||||
|
/// </summary>
|
||||||
|
public interface IRobotTaskRobotStatusService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Изменить статус выполнения задания роботом по ИД задания
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<RobotConfigurationResult> ChangeStatusAsync(ChangeRobotStatus request);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ using PARR.Core.Repositories.Interfaces.JobRepositories;
|
|||||||
using PARR.Core.Repositories.Interfaces.RobotRepositories;
|
using PARR.Core.Repositories.Interfaces.RobotRepositories;
|
||||||
using PARR.Core.Repositories.Interfaces.Schedule;
|
using PARR.Core.Repositories.Interfaces.Schedule;
|
||||||
using PARR.Core.Repositories.Interfaces.TaskRepositories;
|
using PARR.Core.Repositories.Interfaces.TaskRepositories;
|
||||||
|
using PARR.Core.Repositories.Interfaces.TemplateRepositories;
|
||||||
using PARR.Core.Repositories.Interfaces.Unit;
|
using PARR.Core.Repositories.Interfaces.Unit;
|
||||||
using PARR.DAL.Configurations.DbSettings;
|
using PARR.DAL.Configurations.DbSettings;
|
||||||
using PARR.DAL.Context;
|
using PARR.DAL.Context;
|
||||||
@@ -18,6 +19,7 @@ using PARR.DAL.Repositories.JobRepositories;
|
|||||||
using PARR.DAL.Repositories.RobotRepositories;
|
using PARR.DAL.Repositories.RobotRepositories;
|
||||||
using PARR.DAL.Repositories.Schedule;
|
using PARR.DAL.Repositories.Schedule;
|
||||||
using PARR.DAL.Repositories.TaskRepositories;
|
using PARR.DAL.Repositories.TaskRepositories;
|
||||||
|
using PARR.DAL.Repositories.TemplateRepositories;
|
||||||
using PARR.DAL.Repositories.Unit;
|
using PARR.DAL.Repositories.Unit;
|
||||||
using PARR.Domain.Settings;
|
using PARR.Domain.Settings;
|
||||||
|
|
||||||
@@ -142,6 +144,12 @@ namespace PARR.DAL
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Templates
|
||||||
|
|
||||||
|
services.AddScoped<ITemplateRenamePendingRepository, TemplateRenamePendingRepository>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
//services.AddTransient<INextRunModifierService, NextRunModifierService>();
|
//services.AddTransient<INextRunModifierService, NextRunModifierService>();
|
||||||
|
|
||||||
#region NextRun Services
|
#region NextRun Services
|
||||||
|
|||||||
@@ -15,23 +15,13 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
{
|
{
|
||||||
internal abstract class BaseRepository<T> : IBaseRepository<T> where T : class, IBaseEntity
|
internal abstract class BaseRepository<T> : IBaseRepository<T> where T : class, IBaseEntity
|
||||||
{
|
{
|
||||||
//private readonly ILogger<BaseRepository<T>> logger;
|
protected readonly ILogger _logger;
|
||||||
|
|
||||||
//protected abstract DbSet<T> EntitySet { get; }
|
|
||||||
//protected abstract DataContext EntitiContext { get; }
|
|
||||||
|
|
||||||
//public BaseRepository(ILogger<BaseRepository<T>> logger)
|
|
||||||
//{
|
|
||||||
// this.logger = logger;
|
|
||||||
//}
|
|
||||||
|
|
||||||
protected readonly ILogger logger;
|
|
||||||
protected readonly DbSet<T> EntitySet;
|
protected readonly DbSet<T> EntitySet;
|
||||||
protected readonly DataContext EntityContext;
|
protected readonly DataContext EntityContext;
|
||||||
|
|
||||||
protected BaseRepository(ILogger logger, DataContext dataContext)
|
protected BaseRepository(ILogger logger, DataContext dataContext)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this._logger = logger;
|
||||||
this.EntityContext = dataContext;
|
this.EntityContext = dataContext;
|
||||||
this.EntitySet = dataContext.Set<T>();
|
this.EntitySet = dataContext.Set<T>();
|
||||||
}
|
}
|
||||||
@@ -39,7 +29,7 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
|
|
||||||
public virtual async Task<bool> AddRangeAsync(List<T> objs)
|
public virtual async Task<bool> AddRangeAsync(List<T> objs)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Начинаю добавление диапазона объектов типа {EntityType}, количество: {Count}",
|
_logger.LogDebug("Начинаю добавление диапазона объектов типа {EntityType}, количество: {Count}",
|
||||||
typeof(T).Name, objs.Count);
|
typeof(T).Name, objs.Count);
|
||||||
|
|
||||||
objs.ForEach(item => item.DateCreated = DateTimeOffset.UtcNow);
|
objs.ForEach(item => item.DateCreated = DateTimeOffset.UtcNow);
|
||||||
@@ -47,26 +37,26 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await EntitySet.AddRangeAsync(objs);
|
await EntitySet.AddRangeAsync(objs);
|
||||||
logger.LogDebug("Успешно добавлено {Count} объектов типа {EntityType}",
|
_logger.LogDebug("Успешно добавлено {Count} объектов типа {EntityType}",
|
||||||
objs.Count, typeof(T).Name);
|
objs.Count, typeof(T).Name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, "Ошибка при добавлении диапазона объектов типа {EntityType}", typeof(T).Name);
|
_logger.LogError(ex, "Ошибка при добавлении диапазона объектов типа {EntityType}", typeof(T).Name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> CommitAsync(IHistoryInitiator? initiator = null)
|
public async Task<bool> CommitAsync(IHistoryInitiator? initiator = null)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Начинаю сохранение изменений в БД для объектов типа {EntityType}", typeof(T).Name);
|
_logger.LogDebug("Начинаю сохранение изменений в БД для объектов типа {EntityType}", typeof(T).Name);
|
||||||
|
|
||||||
#region Изменения
|
#region Изменения
|
||||||
var modifiedEntrities = EntityContext.ChangeTracker.Entries()
|
var modifiedEntrities = EntityContext.ChangeTracker.Entries()
|
||||||
.Where(t => t.State == EntityState.Modified/* || t.State == EntityState.Deleted*/);
|
.Where(t => t.State == EntityState.Modified/* || t.State == EntityState.Deleted*/);
|
||||||
|
|
||||||
logger.LogDebug("Найдено {Count} измененных сущностей для обработки истории", modifiedEntrities.Count());
|
_logger.LogDebug("Найдено {Count} измененных сущностей для обработки истории", modifiedEntrities.Count());
|
||||||
|
|
||||||
foreach (var obj in modifiedEntrities)
|
foreach (var obj in modifiedEntrities)
|
||||||
{
|
{
|
||||||
@@ -83,13 +73,13 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var changedCount = await EntityContext.SaveChangesAsync();
|
var changedCount = await EntityContext.SaveChangesAsync();
|
||||||
logger.LogDebug("Успешно сохранено {ChangedCount} изменений в БД для объектов типа {EntityType}",
|
_logger.LogDebug("Успешно сохранено {ChangedCount} изменений в БД для объектов типа {EntityType}",
|
||||||
changedCount, typeof(T).Name);
|
changedCount, typeof(T).Name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, "Ошибка при сохранении изменений в БД для объектов типа {EntityType}", typeof(T).Name);
|
_logger.LogError(ex, "Ошибка при сохранении изменений в БД для объектов типа {EntityType}", typeof(T).Name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,14 +94,14 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
if (initiator == null)
|
if (initiator == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
logger.LogDebug("Устанавливаю инициатора для изменений");
|
_logger.LogDebug("Устанавливаю инициатора для изменений");
|
||||||
|
|
||||||
// Задаем инициатора только для новых и измененных записей
|
// Задаем инициатора только для новых и измененных записей
|
||||||
var entrities = EntityContext.ChangeTracker.Entries()
|
var entrities = EntityContext.ChangeTracker.Entries()
|
||||||
.Where(t => t.State == EntityState.Modified || t.State == EntityState.Added);
|
.Where(t => t.State == EntityState.Modified || t.State == EntityState.Added);
|
||||||
|
|
||||||
var entityCount = entrities.Count();
|
var entityCount = entrities.Count();
|
||||||
logger.LogDebug("Найдено {Count} сущностей для установки инициатора", entityCount);
|
_logger.LogDebug("Найдено {Count} сущностей для установки инициатора", entityCount);
|
||||||
|
|
||||||
// смотрим есть ли у объекта интерфейс IHistoryInitiator, если есть, задаём значения
|
// смотрим есть ли у объекта интерфейс IHistoryInitiator, если есть, задаём значения
|
||||||
foreach (var obj in entrities)
|
foreach (var obj in entrities)
|
||||||
@@ -123,7 +113,7 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
(obj.Entity as IHistoryInitiator)!.InitiatorParrComponentId = initiator?.InitiatorParrComponentId ?? null;
|
(obj.Entity as IHistoryInitiator)!.InitiatorParrComponentId = initiator?.InitiatorParrComponentId ?? null;
|
||||||
(obj.Entity as IHistoryInitiator)!.InitiatorComment = initiator?.InitiatorComment ?? null;
|
(obj.Entity as IHistoryInitiator)!.InitiatorComment = initiator?.InitiatorComment ?? null;
|
||||||
|
|
||||||
logger.LogDebug("Установлен инициатор для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
_logger.LogDebug("Установлен инициатор для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,12 +140,12 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
|
|
||||||
if (!isManual)
|
if (!isManual)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Обновляю DateModified для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
_logger.LogDebug("Обновляю DateModified для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||||
entity.DateModified = DateTimeOffset.UtcNow;
|
entity.DateModified = DateTimeOffset.UtcNow;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.LogDebug("Пропуск обновления DateModified (ManualControl) для {EntityType}", entityType.Name);
|
_logger.LogDebug("Пропуск обновления DateModified (ManualControl) для {EntityType}", entityType.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,7 +156,7 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
private void TableHistoryResolver(EntityEntry obj)
|
private void TableHistoryResolver(EntityEntry obj)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Проверяю необходимость создания истории для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
_logger.LogDebug("Проверяю необходимость создания истории для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||||
|
|
||||||
var myHistoryInterface = obj.Entity.GetType().GetInterfaces()
|
var myHistoryInterface = obj.Entity.GetType().GetInterfaces()
|
||||||
.Where(t => t.IsGenericType)
|
.Where(t => t.IsGenericType)
|
||||||
@@ -176,7 +166,7 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
// у этого объекта нет интерфейса IMyHistory<>. Не ведем историю
|
// у этого объекта нет интерфейса IMyHistory<>. Не ведем историю
|
||||||
if (myHistoryInterface == null)
|
if (myHistoryInterface == null)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Сущность типа {EntityType} не требует ведения истории", obj.Entity.GetType().Name);
|
_logger.LogDebug("Сущность типа {EntityType} не требует ведения истории", obj.Entity.GetType().Name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,13 +176,13 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
var historyType = myHistoryInterface.GetGenericArguments().First();
|
var historyType = myHistoryInterface.GetGenericArguments().First();
|
||||||
var historyProps = historyType.GetProperties(/*BindingFlags.DeclaredOnly | */ /*BindingFlags.Public*/).ToList();
|
var historyProps = historyType.GetProperties(/*BindingFlags.DeclaredOnly | */ /*BindingFlags.Public*/).ToList();
|
||||||
|
|
||||||
logger.LogDebug("Создаю историю для сущности типа {EntityType}, тип истории: {HistoryType}",
|
_logger.LogDebug("Создаю историю для сущности типа {EntityType}, тип истории: {HistoryType}",
|
||||||
obj.Entity.GetType().Name, historyType.Name);
|
obj.Entity.GetType().Name, historyType.Name);
|
||||||
|
|
||||||
var historyInstance = Activator.CreateInstance(historyType);
|
var historyInstance = Activator.CreateInstance(historyType);
|
||||||
if (historyInstance == null)
|
if (historyInstance == null)
|
||||||
{
|
{
|
||||||
logger.LogError("Не смог создать инстанс для ведения истории {HistoryType}", historyType.Name);
|
_logger.LogError("Не смог создать инстанс для ведения истории {HistoryType}", historyType.Name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,11 +198,11 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
EntityContext.Add(historyInstance);
|
EntityContext.Add(historyInstance);
|
||||||
logger.LogDebug("История добавлена для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
_logger.LogDebug("История добавлена для сущности типа {EntityType}", obj.Entity.GetType().Name);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, "Ошибка при добавлении объекта в историю {HistoryType}", historyType.Name);
|
_logger.LogError(ex, "Ошибка при добавлении объекта в историю {HistoryType}", historyType.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +215,7 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
/// <param name="propsList"></param>
|
/// <param name="propsList"></param>
|
||||||
private void FillHistoryProps(EntityEntry originalObj, ref object historyInstance, List<PropertyInfo> propsList)
|
private void FillHistoryProps(EntityEntry originalObj, ref object historyInstance, List<PropertyInfo> propsList)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Заполняю историю для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
|
_logger.LogDebug("Заполняю историю для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
|
||||||
|
|
||||||
foreach (var prop in propsList)
|
foreach (var prop in propsList)
|
||||||
{
|
{
|
||||||
@@ -250,7 +240,7 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
histProp.SetValue(historyInstance, origValues);
|
histProp.SetValue(historyInstance, origValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.LogDebug("Завершено заполнение истории для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
|
_logger.LogDebug("Завершено заполнение истории для сущности типа {EntityType}", originalObj.Entity.GetType().Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -266,14 +256,14 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
var histProp = instanceObj.GetType().GetProperty(propName);
|
var histProp = instanceObj.GetType().GetProperty(propName);
|
||||||
if (histProp == null)
|
if (histProp == null)
|
||||||
{
|
{
|
||||||
logger.LogError("При изменении объекта для БД, не найдено свойство {PropertyName}", propName);
|
_logger.LogError("При изменении объекта для БД, не найдено свойство {PropertyName}", propName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// сравним типы
|
// сравним типы
|
||||||
if (histProp.PropertyType != typeof(TValue))
|
if (histProp.PropertyType != typeof(TValue))
|
||||||
{
|
{
|
||||||
logger.LogError("При изменении объекта для БД, не совпадают типы у свойства {PropertyName}, {PropertyType}!={ValueType}",
|
_logger.LogError("При изменении объекта для БД, не совпадают типы у свойства {PropertyName}, {PropertyType}!={ValueType}",
|
||||||
propName, histProp.PropertyType.Name, typeof(TValue).Name);
|
propName, histProp.PropertyType.Name, typeof(TValue).Name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -340,7 +330,7 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
|
|
||||||
public virtual async Task<bool> CreateAsync(T obj)
|
public virtual async Task<bool> CreateAsync(T obj)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Начинаю создание объекта типа {EntityType}", typeof(T).Name);
|
_logger.LogDebug("Начинаю создание объекта типа {EntityType}", typeof(T).Name);
|
||||||
|
|
||||||
if (obj.DateCreated == DateTimeOffset.MinValue)
|
if (obj.DateCreated == DateTimeOffset.MinValue)
|
||||||
obj.DateCreated = DateTimeOffset.UtcNow;
|
obj.DateCreated = DateTimeOffset.UtcNow;
|
||||||
@@ -348,73 +338,73 @@ namespace PARR.DAL.Repositories.Base
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await EntitySet.AddAsync(obj);
|
await EntitySet.AddAsync(obj);
|
||||||
logger.LogDebug("Объект типа {EntityType} добавлен в контекст", typeof(T).Name);
|
_logger.LogDebug("Объект типа {EntityType} добавлен в контекст", typeof(T).Name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, "Ошибка при добавлении объекта типа {EntityType} в БД", typeof(T).Name);
|
_logger.LogError(ex, "Ошибка при добавлении объекта типа {EntityType} в БД", typeof(T).Name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool Delete(T obj)
|
public virtual bool Delete(T obj)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Начинаю удаление объекта типа {EntityType}", obj.GetType().Name);
|
_logger.LogDebug("Начинаю удаление объекта типа {EntityType}", obj.GetType().Name);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
EntitySet.Remove(obj);
|
EntitySet.Remove(obj);
|
||||||
logger.LogDebug("Объект типа {EntityType} удален из контекста", obj.GetType().Name);
|
_logger.LogDebug("Объект типа {EntityType} удален из контекста", obj.GetType().Name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД", obj.GetType().Name);
|
_logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД", obj.GetType().Name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<bool> DeleteAsync(Guid id)
|
public virtual async Task<bool> DeleteAsync(Guid id)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Начинаю удаление объекта типа {EntityType} по ID: {Id}", typeof(T).Name, id);
|
_logger.LogDebug("Начинаю удаление объекта типа {EntityType} по ID: {Id}", typeof(T).Name, id);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var exist = await GetAsync(id);
|
var exist = await GetAsync(id);
|
||||||
if (exist == null)
|
if (exist == null)
|
||||||
{
|
{
|
||||||
logger.LogError("Ошибка при удалении из БД. Не найдена запись в БД типа {EntityType} с id: {Id}",
|
_logger.LogError("Ошибка при удалении из БД. Не найдена запись в БД типа {EntityType} с id: {Id}",
|
||||||
typeof(T).Name, id);
|
typeof(T).Name, id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntitySet.Remove(exist);
|
EntitySet.Remove(exist);
|
||||||
logger.LogDebug("Объект типа {EntityType} с ID {Id} удален из контекста", typeof(T).Name, id);
|
_logger.LogDebug("Объект типа {EntityType} с ID {Id} удален из контекста", typeof(T).Name, id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД по ID: {Id}", typeof(T).Name, id);
|
_logger.LogError(ex, "Ошибка при удалении объекта типа {EntityType} из БД по ID: {Id}", typeof(T).Name, id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual IQueryable<T> Get()
|
public virtual IQueryable<T> Get()
|
||||||
{
|
{
|
||||||
logger.LogDebug("Получаю набор объектов типа {EntityType}", typeof(T).Name);
|
_logger.LogDebug("Получаю набор объектов типа {EntityType}", typeof(T).Name);
|
||||||
return EntitySet;
|
return EntitySet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<T?> GetAsync(Guid id)
|
public virtual async Task<T?> GetAsync(Guid id)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Получаю объект типа {EntityType} по ID: {Id}", typeof(T).Name, id);
|
_logger.LogDebug("Получаю объект типа {EntityType} по ID: {Id}", typeof(T).Name, id);
|
||||||
return await EntitySet.FirstOrDefaultAsync(t => t.Id == id);
|
return await EntitySet.FirstOrDefaultAsync(t => t.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual IQueryable<T> GetPage(IQueryable<T> query, PaginationFilter paginationFilter)
|
public virtual IQueryable<T> GetPage(IQueryable<T> query, PaginationFilter paginationFilter)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Получаю страницу объектов типа {EntityType}, страница: {PageNumber}, размер: {PageSize}",
|
_logger.LogDebug("Получаю страницу объектов типа {EntityType}, страница: {PageNumber}, размер: {PageSize}",
|
||||||
typeof(T).Name, paginationFilter.PageNumber, paginationFilter.PageSize);
|
typeof(T).Name, paginationFilter.PageNumber, paginationFilter.PageSize);
|
||||||
|
|
||||||
int skip = (paginationFilter.PageNumber - 1) * paginationFilter.PageSize;
|
int skip = (paginationFilter.PageNumber - 1) * paginationFilter.PageSize;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using InfluxDB.Client.Api.Domain;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using PARR.Core.Repositories.Interfaces;
|
using PARR.Core.Repositories.Interfaces;
|
||||||
using PARR.DAL.Context;
|
using PARR.DAL.Context;
|
||||||
using PARR.DAL.Repositories.Base;
|
using PARR.DAL.Repositories.Base;
|
||||||
using PARR.Domain.Entities;
|
using PARR.Domain.Entities;
|
||||||
|
using PARR.Domain.Entities.RobotEntities;
|
||||||
using PARR.Domain.Enums;
|
using PARR.Domain.Enums;
|
||||||
using PARR.Domain.Settings;
|
using PARR.Domain.Settings;
|
||||||
|
|
||||||
@@ -52,7 +54,7 @@ namespace PARR.DAL.Repositories
|
|||||||
? ((TaskStatusEnum)taskStatusValue).ToString()
|
? ((TaskStatusEnum)taskStatusValue).ToString()
|
||||||
: $"Unknown ({taskStatusValue})";
|
: $"Unknown ({taskStatusValue})";
|
||||||
|
|
||||||
logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как текущий статус {currentStatus}",
|
_logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как текущий статус {currentStatus}",
|
||||||
updatingStatus, configuration.Id, configuration.TemplateId, taskStatusName);
|
updatingStatus, configuration.Id, configuration.TemplateId, taskStatusName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -63,13 +65,13 @@ namespace PARR.DAL.Repositories
|
|||||||
// есть ли связь у config с templetes, может инклуда нет, мало ли
|
// есть ли связь у config с templetes, может инклуда нет, мало ли
|
||||||
if (configuration.Template == null)
|
if (configuration.Template == null)
|
||||||
{
|
{
|
||||||
logger.LogWarning("При изменении статуса задания на обновление шаблона, не смог проверить наличае ScheduleEsppId, так как нет Include с Templates. Пропустил эту проверку. configurationId: {configurationId}", configuration.Id);
|
_logger.LogWarning("При изменении статуса задания на обновление шаблона, не смог проверить наличае ScheduleEsppId, так как нет Include с Templates. Пропустил эту проверку. configurationId: {configurationId}", configuration.Id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (configuration.Template.ScheduleEsppId == null)
|
if (configuration.Template.ScheduleEsppId == null)
|
||||||
{
|
{
|
||||||
logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как у шаблона отсутсвтует ScheduleEsppId=null",
|
_logger.LogInformation("Нельзя установить статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}, так как у шаблона отсутсвтует ScheduleEsppId=null",
|
||||||
updatingStatus, configuration.Id, configuration.TemplateId);
|
updatingStatus, configuration.Id, configuration.TemplateId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -78,7 +80,7 @@ namespace PARR.DAL.Repositories
|
|||||||
|
|
||||||
// Статус ОК, можно ставить Updating
|
// Статус ОК, можно ставить Updating
|
||||||
ChangeTaskStatus(updatingStatus, configuration);
|
ChangeTaskStatus(updatingStatus, configuration);
|
||||||
logger.LogInformation("Установлен статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}", updatingStatus, configuration.Id, configuration.TemplateId);
|
_logger.LogInformation("Установлен статус {newStatus} для конфигурации {configurationId}, templateId: {templateId}", updatingStatus, configuration.Id, configuration.TemplateId);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -94,8 +96,8 @@ namespace PARR.DAL.Repositories
|
|||||||
configuration.AttemptsNumber++;
|
configuration.AttemptsNumber++;
|
||||||
configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
|
configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
|
||||||
break;
|
break;
|
||||||
//case RobotStatusEnum.Error:
|
case RobotStatusEnum.Error:
|
||||||
// break;
|
break;
|
||||||
case RobotStatusEnum.Complete:
|
case RobotStatusEnum.Complete:
|
||||||
configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
|
configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
|
||||||
break;
|
break;
|
||||||
@@ -108,6 +110,14 @@ namespace PARR.DAL.Repositories
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetErrorRobotStatusAndMaxAttempts(RobotConfiguration configuration)
|
||||||
|
{
|
||||||
|
ChangeRobotStatus(RobotStatusEnum.Error, configuration);
|
||||||
|
|
||||||
|
configuration.AttemptsNumber = settingsFromDb.RobotAttemptsNumber;
|
||||||
|
configuration.LastRobotStatusUpdated = DateTimeOffset.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<bool> SetInProgressStatusAsync(Guid id)
|
public async Task<bool> SetInProgressStatusAsync(Guid id)
|
||||||
{
|
{
|
||||||
@@ -144,7 +154,7 @@ namespace PARR.DAL.Repositories
|
|||||||
|
|
||||||
if (config == null)
|
if (config == null)
|
||||||
{
|
{
|
||||||
logger.LogError($"У шаблона нет конфигурации роботов. TemplateId: {template.Id}");
|
_logger.LogError($"У шаблона нет конфигурации роботов. TemplateId: {template.Id}");
|
||||||
throw new Exception($"У шаблона нет конфигурации роботов. TemplateId: {template.Id}");
|
throw new Exception($"У шаблона нет конфигурации роботов. TemplateId: {template.Id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,25 +170,82 @@ namespace PARR.DAL.Repositories
|
|||||||
|
|
||||||
var endDate = DateTimeOffset.UtcNow.Add(-robotWaitTime);
|
var endDate = DateTimeOffset.UtcNow.Add(-robotWaitTime);
|
||||||
|
|
||||||
var configObjs = await EntitySet.Where(t =>
|
var expiredConfigs = await EntitySet.Where(t =>
|
||||||
t.RobotStatusCode == (int)RobotStatusEnum.InProgress
|
t.RobotStatusCode == (int)RobotStatusEnum.InProgress
|
||||||
&& t.AttemptsNumber >= robotAttemptsNumber
|
&& t.AttemptsNumber >= robotAttemptsNumber
|
||||||
&& t.LastRobotStatusUpdated <= endDate
|
&& t.LastRobotStatusUpdated <= endDate
|
||||||
).ToListAsync();
|
).ToListAsync();
|
||||||
|
|
||||||
if (!configObjs.Any())
|
if (!expiredConfigs.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
configObjs.ForEach(item =>
|
foreach (var item in expiredConfigs)
|
||||||
{
|
{
|
||||||
ChangeRobotStatus(RobotStatusEnum.Error, item);
|
ChangeRobotStatus(RobotStatusEnum.Error, item);
|
||||||
logger.LogInformation($"Устанавливаю RobotStatus: {RobotStatusEnum.Error} для RobotConfigurationId {item.Id}");
|
_logger.LogInformation("Устанавливаю статус RobotStatus: {RobotStatus} для RobotConfigurationId: {RobotConfigurationId}", RobotStatusEnum.Error, item.Id);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
#region Ищем, есть ли связанные шаблоны, которые должны переименоваться, им тоже нужно установить статус ошибки, но только для Шаблонов
|
||||||
|
|
||||||
|
// Проактивная обработка связанных шаблонов переименования Old->New
|
||||||
|
// Если старый шаблон умен, мы должны сразу убить (!!!замочить!!!) и новый (целевой), чтобы он не висел вечно в ожидании.
|
||||||
|
|
||||||
|
var expiredTemplateIds = expiredConfigs
|
||||||
|
.Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder)
|
||||||
|
.Select(t => t.TemplateId)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (expiredTemplateIds.Any())
|
||||||
|
{
|
||||||
|
// Находим OldName для этих шаблонов из таблицы переименований.
|
||||||
|
var oldNamesToFail = await EntityContext.Templates
|
||||||
|
.Where(t => expiredTemplateIds.Contains(t.Id) && t.TemplateRenamePending != null)
|
||||||
|
.Select(t => t.TemplateRenamePending!.OldName)
|
||||||
|
.Distinct()
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Находим целевые (новые задачи), имена которых совпадают с найденными OldName
|
||||||
|
if (oldNamesToFail.Any())
|
||||||
|
{
|
||||||
|
var targetConfigs = await EntitySet
|
||||||
|
.Where(t =>
|
||||||
|
t.RobotCode == (int)RobotsEnum.TemplateOrder
|
||||||
|
&& t.RobotStatusCode != (int)RobotStatusEnum.Error // Не трогаем те, что уже в ошибке
|
||||||
|
&& oldNamesToFail.Contains(t.Template!.Name)
|
||||||
|
).ToListAsync();
|
||||||
|
|
||||||
|
foreach (var item in targetConfigs)
|
||||||
|
{
|
||||||
|
SetErrorRobotStatusAndMaxAttempts(item);
|
||||||
|
|
||||||
|
// Пишем в лог роботу
|
||||||
|
var history = new RobotHistory
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
HistoryLevel = (int)RobotStatusEnum.Error,
|
||||||
|
TaskStatusCode = item.TaskStatusCode,
|
||||||
|
RobotConfigurationId = item.Id,
|
||||||
|
RobotIp = null,
|
||||||
|
RobotId = ParrComponentsEnum.Api.ToString(),
|
||||||
|
RobotMessage = "[RobotConfigurationRepository] Установлен статус ошибки, так как не переименован связанный шаблон"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Синхронный Add работает быстрее и безопаснее внутри цикла
|
||||||
|
EntityContext.RobotHistories.Add(history);
|
||||||
|
|
||||||
|
_logger.LogInformation("Проактивно установлен статус {Status} для целевого задания RobotConfigurationID: {Id} из-за ошибки старого шаблона.", RobotStatusEnum.Error, item.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
var result = await CommitAsync();
|
var result = await CommitAsync();
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
logger.LogError($"Ошибка при сохранении изменений RobotStatus для RobotConfigurationId: item.Id, RobotStatus: {RobotStatusEnum.Error}");
|
_logger.LogError("Ошибка при сохранении изменений RobotStatus для просроченных заданий. Откат транзакции.");
|
||||||
|
//else
|
||||||
|
// logger.LogInformation("Успешно обработано и переведено в статус Ошибки просроченных заданий: {Count} шт.", configObjs.Count + linksCount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PARR.Core.Repositories.Interfaces.TemplateRepositories;
|
||||||
|
using PARR.DAL.Context;
|
||||||
|
using PARR.Domain.Entities.TemplateEntities;
|
||||||
|
|
||||||
|
namespace PARR.DAL.Repositories.TemplateRepositories
|
||||||
|
{
|
||||||
|
internal class TemplateRenamePendingRepository : ITemplateRenamePendingRepository
|
||||||
|
{
|
||||||
|
private readonly DataContext _dataContext;
|
||||||
|
private readonly ILogger<TemplateRenamePendingRepository> _logger;
|
||||||
|
|
||||||
|
public TemplateRenamePendingRepository(
|
||||||
|
DataContext dataContext,
|
||||||
|
ILogger<TemplateRenamePendingRepository> logger
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_dataContext = dataContext;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public IQueryable<TemplateRenamePending> Get()
|
||||||
|
{
|
||||||
|
return _dataContext.TemplateRenamePendings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(TemplateRenamePending obj)
|
||||||
|
{
|
||||||
|
_dataContext.TemplateRenamePendings.Remove(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<bool> CreateAsync(TemplateRenamePending obj)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _dataContext.TemplateRenamePendings.AddAsync(obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Ошибка при добавлении объекта типа TemplateRenamePending в БД");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ namespace PARR.DAL.Repositories
|
|||||||
|
|
||||||
public async Task<Template?> GetTemplateByNameAsync(string name)
|
public async Task<Template?> GetTemplateByNameAsync(string name)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Поиск шаблона по имени: {TemplateName}", name);
|
_logger.LogDebug("Поиск шаблона по имени: {TemplateName}", name);
|
||||||
|
|
||||||
var template = await GetWithIncludes()
|
var template = await GetWithIncludes()
|
||||||
.Include(t => t.RobotConfigurations)
|
.Include(t => t.RobotConfigurations)
|
||||||
@@ -24,11 +24,11 @@ namespace PARR.DAL.Repositories
|
|||||||
|
|
||||||
if (template != null)
|
if (template != null)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Шаблон найден: {TemplateId}, имя: {TemplateName}", template.Id, template.Name);
|
_logger.LogDebug("Шаблон найден: {TemplateId}, имя: {TemplateName}", template.Id, template.Name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.LogDebug("Шаблон с именем {TemplateName} не найден", name);
|
_logger.LogDebug("Шаблон с именем {TemplateName} не найден", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return template;
|
return template;
|
||||||
@@ -36,7 +36,7 @@ namespace PARR.DAL.Repositories
|
|||||||
|
|
||||||
public IQueryable<Template> GetWithIncludes()
|
public IQueryable<Template> GetWithIncludes()
|
||||||
{
|
{
|
||||||
logger.LogDebug("Получаю шаблоны с include связями");
|
_logger.LogDebug("Получаю шаблоны с include связями");
|
||||||
|
|
||||||
return Get()
|
return Get()
|
||||||
.Include(h => h.Unit)
|
.Include(h => h.Unit)
|
||||||
@@ -60,7 +60,7 @@ namespace PARR.DAL.Repositories
|
|||||||
|
|
||||||
public override Task<bool> CreateAsync(Template obj)
|
public override Task<bool> CreateAsync(Template obj)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Создание шаблона: {TemplateName}", obj.Name);
|
_logger.LogDebug("Создание шаблона: {TemplateName}", obj.Name);
|
||||||
|
|
||||||
// добавление роботов для шаблона
|
// добавление роботов для шаблона
|
||||||
obj.RobotConfigurations = new List<RobotConfiguration>
|
obj.RobotConfigurations = new List<RobotConfiguration>
|
||||||
@@ -92,7 +92,7 @@ namespace PARR.DAL.Repositories
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.LogDebug("Добавлены роботы для шаблона {TemplateName}", obj.Name);
|
_logger.LogDebug("Добавлены роботы для шаблона {TemplateName}", obj.Name);
|
||||||
|
|
||||||
return base.CreateAsync(obj);
|
return base.CreateAsync(obj);
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ namespace PARR.DAL.Repositories
|
|||||||
|
|
||||||
public async Task<Guid?> ReserveUnusedTemplateAsync(Guid newUnitId, HistoryInitiator initiator)
|
public async Task<Guid?> ReserveUnusedTemplateAsync(Guid newUnitId, HistoryInitiator initiator)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Резервирую неиспользуемый шаблон для UnitId: {UnitId}", newUnitId);
|
_logger.LogDebug("Резервирую неиспользуемый шаблон для UnitId: {UnitId}", newUnitId);
|
||||||
|
|
||||||
// Явная транзакция гарантирует атомарность UPDATE + подзапроса
|
// Явная транзакция гарантирует атомарность UPDATE + подзапроса
|
||||||
await using var transaction = await EntityContext.Database.BeginTransactionAsync();
|
await using var transaction = await EntityContext.Database.BeginTransactionAsync();
|
||||||
@@ -167,18 +167,18 @@ namespace PARR.DAL.Repositories
|
|||||||
|
|
||||||
if (reservedTemplateId != Guid.Empty)
|
if (reservedTemplateId != Guid.Empty)
|
||||||
{
|
{
|
||||||
logger.LogInformation("Успешно зарезервирован шаблон с ID: {TemplateId} для UnitId: {UnitId}",
|
_logger.LogInformation("Успешно зарезервирован шаблон с ID: {TemplateId} для UnitId: {UnitId}",
|
||||||
reservedTemplateId, newUnitId);
|
reservedTemplateId, newUnitId);
|
||||||
return reservedTemplateId;
|
return reservedTemplateId;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.LogDebug("Не удалось зарезервировать шаблон для UnitId: {UnitId}", newUnitId);
|
_logger.LogDebug("Не удалось зарезервировать шаблон для UnitId: {UnitId}", newUnitId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await transaction.RollbackAsync();
|
await transaction.RollbackAsync();
|
||||||
logger.LogError(ex, "Ошибка при резервировании шаблона для UnitId: {UnitId}", newUnitId);
|
_logger.LogError(ex, "Ошибка при резервировании шаблона для UnitId: {UnitId}", newUnitId);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ namespace PARR.DAL.Repositories
|
|||||||
var exist = await GetAsync(id);
|
var exist = await GetAsync(id);
|
||||||
if (exist == null)
|
if (exist == null)
|
||||||
{
|
{
|
||||||
logger.LogError($"Ошибка при удалении из БД. Не найдена запись в БД с id: {id}");
|
_logger.LogError($"Ошибка при удалении из БД. Не найдена запись в БД с id: {id}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
PARR.Domain/DTOs/RobotTaskRobotStatus/ChangeRobotStatus.cs
Normal file
13
PARR.Domain/DTOs/RobotTaskRobotStatus/ChangeRobotStatus.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using PARR.Domain.Enums;
|
||||||
|
|
||||||
|
namespace PARR.Domain.DTOs.RobotTaskRobotStatus
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Изменить статус задания робота
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="TaskId"></param>
|
||||||
|
/// <param name="RobotStatusCode"></param>
|
||||||
|
/// <param name="RobotId">Идентификатор робота</param>
|
||||||
|
/// <param name="RobotIp">IP адрес робота</param>
|
||||||
|
public record ChangeRobotStatus(Guid TaskId, RobotStatusEnum RobotStatusCode, string? RobotId, string? RobotIp);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using PARR.Domain.DTOs.Shared;
|
||||||
|
|
||||||
|
namespace PARR.Domain.DTOs.RobotTaskRobotStatus
|
||||||
|
{
|
||||||
|
public record RobotConfigurationResult
|
||||||
|
{
|
||||||
|
public Guid Id { get; init; }
|
||||||
|
|
||||||
|
public DateTimeOffset DateCreated { get; init; }
|
||||||
|
|
||||||
|
public Guid TemplateId { get; init; }
|
||||||
|
|
||||||
|
public RobotResult? Robot { get; init; }
|
||||||
|
|
||||||
|
public RobotTaskStatusResult? TaskStatus { get; init; }
|
||||||
|
|
||||||
|
public RobotStatusResult? RobotStatus { get; init; }
|
||||||
|
|
||||||
|
public int AttemptsNumber { get; init; }
|
||||||
|
|
||||||
|
public DateTimeOffset? LastRobotStatusUpdated { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
9
PARR.Domain/DTOs/Shared/RobotResult.cs
Normal file
9
PARR.Domain/DTOs/Shared/RobotResult.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace PARR.Domain.DTOs.Shared
|
||||||
|
{
|
||||||
|
public record RobotResult
|
||||||
|
{
|
||||||
|
public int Code { get; init; }
|
||||||
|
public required string Name { get; init; }
|
||||||
|
public required string Description { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
9
PARR.Domain/DTOs/Shared/RobotStatusResult.cs
Normal file
9
PARR.Domain/DTOs/Shared/RobotStatusResult.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace PARR.Domain.DTOs.Shared
|
||||||
|
{
|
||||||
|
public record RobotStatusResult
|
||||||
|
{
|
||||||
|
public int Code { get; init; }
|
||||||
|
public string? Name { get; init; }
|
||||||
|
public string? Description { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
9
PARR.Domain/DTOs/Shared/RobotTaskStatusResult.cs
Normal file
9
PARR.Domain/DTOs/Shared/RobotTaskStatusResult.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace PARR.Domain.DTOs.Shared
|
||||||
|
{
|
||||||
|
public record RobotTaskStatusResult
|
||||||
|
{
|
||||||
|
public int Code { get; init; }
|
||||||
|
public required string Name { get; init; }
|
||||||
|
public required string Description { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using PARR.Core.Repositories.Interfaces;
|
using PARR.Core.Repositories.Interfaces;
|
||||||
|
using PARR.Core.Repositories.Interfaces.TemplateRepositories;
|
||||||
using PARR.Core.Services.Shortcodes;
|
using PARR.Core.Services.Shortcodes;
|
||||||
using PARR.Domain.Entities;
|
using PARR.Domain.Entities;
|
||||||
using PARR.Domain.Entities.Base.History;
|
using PARR.Domain.Entities.Base.History;
|
||||||
@@ -14,16 +15,16 @@ namespace PARR.EsppSync
|
|||||||
{
|
{
|
||||||
internal class SyncService<EsppObject> : ISyncService<EsppObject> where EsppObject : class, IEsppObject
|
internal class SyncService<EsppObject> : ISyncService<EsppObject> where EsppObject : class, IEsppObject
|
||||||
{
|
{
|
||||||
private readonly ILogger<SyncService<EsppObject>> logger;
|
private readonly ILogger<SyncService<EsppObject>> _logger;
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
public SyncService(
|
public SyncService(
|
||||||
ILogger<SyncService<EsppObject>> logger,
|
ILogger<SyncService<EsppObject>> logger,
|
||||||
IServiceProvider serviceProvider
|
IServiceProvider serviceProvider
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
_logger = logger;
|
||||||
this.serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -35,11 +36,11 @@ namespace PARR.EsppSync
|
|||||||
AfterParseStringToEsppObjectAsync<EsppObject>? afterParseStringToEsppObjectAsync = null
|
AfterParseStringToEsppObjectAsync<EsppObject>? afterParseStringToEsppObjectAsync = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Получил строку. Начинаю работать. Строка: {String}", str);
|
_logger.LogDebug("Получил строку. Начинаю работать. Строка: {String}", str);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(str))
|
if (string.IsNullOrEmpty(str))
|
||||||
{
|
{
|
||||||
logger.LogWarning("Получил пустую строку, ничего не делаю.");
|
_logger.LogWarning("Получил пустую строку, ничего не делаю.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ namespace PARR.EsppSync
|
|||||||
|
|
||||||
if (esppObject == null)
|
if (esppObject == null)
|
||||||
{
|
{
|
||||||
logger.LogWarning("После парсинга строки, esppObject = null. Дальше ничего не буду делать.");
|
_logger.LogWarning("После парсинга строки, esppObject = null. Дальше ничего не буду делать.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,47 +57,64 @@ namespace PARR.EsppSync
|
|||||||
await afterParseStringToEsppObjectAsync.Invoke(esppObject);
|
await afterParseStringToEsppObjectAsync.Invoke(esppObject);
|
||||||
|
|
||||||
|
|
||||||
using (var scope = serviceProvider.CreateScope())
|
using (var scope = _serviceProvider.CreateScope())
|
||||||
{
|
{
|
||||||
var templateService = GetServiceInScope<ITemplateRepository>(scope);
|
var templateService = scope.ServiceProvider.GetRequiredService<ITemplateRepository>();
|
||||||
var robotConfigurationService = GetServiceInScope<IRobotConfigurationRepository>(scope);
|
var robotConfigurationService = scope.ServiceProvider.GetRequiredService<IRobotConfigurationRepository>();
|
||||||
var shortcodesService = GetServiceInScope<IShortcodesService>(scope);
|
var shortcodesService = scope.ServiceProvider.GetRequiredService<IShortcodesService>();
|
||||||
|
var templateRenamePendingRepository = scope.ServiceProvider.GetRequiredService<ITemplateRenamePendingRepository>();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
#region Проверка, идет ли переименование
|
||||||
|
|
||||||
|
// Если есть у этого шаблона запись в TemplateRenamePending, значит сейчас идет переименование, пропускаем синхронизацию этого шаблона
|
||||||
|
// Если имя этого шаблона находится в таблице TemplateRenamePending, значит идет переименование связанного шаблона, пропускаем синхронизацию этого шаблона
|
||||||
|
var isPartOfRename = await templateRenamePendingRepository.Get()
|
||||||
|
.AnyAsync(t => t.Template.Name == esppObject.TemplateName || t.OldName == esppObject.TemplateName);
|
||||||
|
|
||||||
|
if (isPartOfRename)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Пропускаем синхронизацию '{TemplateName}', так как шаблон ({EsppObject}) участвует в процессе переименования.", esppObject.TemplateName, nameof(EsppObject));
|
||||||
|
// Выходим сразу
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
// Загружаем Template и TemplateForShortcodes в одном запросе
|
// Загружаем Template и TemplateForShortcodes в одном запросе
|
||||||
var query = templateService.Get()
|
var query = templateService.Get()
|
||||||
//.AsNoTracking()
|
.Include(h => h.Unit)
|
||||||
.Include(h => h.Unit)
|
.ThenInclude(t => t!.UnitValues)
|
||||||
.ThenInclude(t => t!.UnitValues)
|
.ThenInclude(t => t.Value)
|
||||||
.ThenInclude(t => t.Value)
|
.Include(h => h.Unit)
|
||||||
.Include(h => h.Unit)
|
.ThenInclude(t => t!.UnitValues)
|
||||||
.ThenInclude(t => t!.UnitValues)
|
.ThenInclude(t => t.Field)
|
||||||
.ThenInclude(t => t.Field)
|
.Include(t => t.RobotConfigurations)
|
||||||
.Include(t => t.RobotConfigurations)
|
.Include(t => t.Job)
|
||||||
.Include(t => t.Job)
|
.ThenInclude(j => j.Group)
|
||||||
.ThenInclude(j => j.Group)
|
.ThenInclude(g => g.GroupType)
|
||||||
.ThenInclude(g => g.GroupType)
|
.Include(t => t.Job)
|
||||||
.Include(t => t.Job)
|
.ThenInclude(t => t.Group)
|
||||||
.ThenInclude(t => t.Group)
|
.ThenInclude(t => t.ScheduleExcludeType)
|
||||||
.ThenInclude(t => t.ScheduleExcludeType)
|
.Include(t => t.Job)
|
||||||
.Include(t => t.Job)
|
.ThenInclude(t => t.Group)
|
||||||
.ThenInclude(t => t.Group)
|
.ThenInclude(t => t.ScheduleExcludeTypeCalendar)
|
||||||
.ThenInclude(t => t.ScheduleExcludeTypeCalendar)
|
.Include(t => t.Job)
|
||||||
.Include(t => t.Job)
|
.ThenInclude(j => j.Tnk)
|
||||||
.ThenInclude(j => j.Tnk)
|
.ThenInclude(s => s!.Subprocess)
|
||||||
.ThenInclude(s => s!.Subprocess)
|
.ThenInclude(p => p!.Process)
|
||||||
.ThenInclude(p => p!.Process)
|
.Include(t => t.UnitsInTemplate);
|
||||||
.Include(t => t.UnitsInTemplate);
|
|
||||||
|
|
||||||
var template = await query.FirstOrDefaultAsync(t => t.Name == esppObject.TemplateName);
|
var template = await query.FirstOrDefaultAsync(t => t.Name == esppObject.TemplateName);
|
||||||
|
|
||||||
if (template == null)
|
if (template == null)
|
||||||
{
|
{
|
||||||
logger.LogWarning("Найден объект в ЕСПП с именем шаблона '{TemplateName}' незарегистрированный в ПАРР. Строка: {String}", esppObject.TemplateName, str);
|
_logger.LogWarning("Найден объект в ЕСПП с именем шаблона '{TemplateName}' незарегистрированный в ПАРР. Строка: {String}", esppObject.TemplateName, str);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var dbObjectInEsppObject = converterDbToEsppObject.Invoke(template);
|
var dbObjectInEsppObject = converterDbToEsppObject.Invoke(template);
|
||||||
|
|
||||||
await ApplyShortcodesAsync(dbObjectInEsppObject, template, shortcodesService);
|
await ApplyShortcodesAsync(dbObjectInEsppObject, template, shortcodesService);
|
||||||
@@ -107,7 +125,7 @@ namespace PARR.EsppSync
|
|||||||
|
|
||||||
if (dbObjectInEsppObject.IsActive == false)
|
if (dbObjectInEsppObject.IsActive == false)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Объект деактивирован в ПАРР. Сравниваем только обязательные поля. {TemplateName}", esppObject.TemplateName);
|
_logger.LogDebug("Объект деактивирован в ПАРР. Сравниваем только обязательные поля. {TemplateName}", esppObject.TemplateName);
|
||||||
var lightDbObj = new EsppLightObject(dbObjectInEsppObject);
|
var lightDbObj = new EsppLightObject(dbObjectInEsppObject);
|
||||||
var lightEsppObject = new EsppLightObject(esppObject);
|
var lightEsppObject = new EsppLightObject(esppObject);
|
||||||
|
|
||||||
@@ -115,7 +133,7 @@ namespace PARR.EsppSync
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.LogDebug("Объект активирован в ПАРР. Сравниваем все поля. {TemplateName}", esppObject.TemplateName);
|
_logger.LogDebug("Объект активирован в ПАРР. Сравниваем все поля. {TemplateName}", esppObject.TemplateName);
|
||||||
isChanged = IsChanged(esppObject, dbObjectInEsppObject, esppObject.TemplateName);
|
isChanged = IsChanged(esppObject, dbObjectInEsppObject, esppObject.TemplateName);
|
||||||
|
|
||||||
// выполняем кастомную дополнительную проверку (только если isChanged==false, чтоб лишний раз не гонять)
|
// выполняем кастомную дополнительную проверку (только если isChanged==false, чтоб лишний раз не гонять)
|
||||||
@@ -127,25 +145,25 @@ namespace PARR.EsppSync
|
|||||||
var isCustomComparision = await customComparisionAsync.Invoke(esppObject, dbObjectInEsppObject, template.Id);
|
var isCustomComparision = await customComparisionAsync.Invoke(esppObject, dbObjectInEsppObject, template.Id);
|
||||||
if (isCustomComparision)
|
if (isCustomComparision)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Дополнительная проверка прошла.");
|
_logger.LogDebug("Дополнительная проверка прошла.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// если дополнительная проверка не прошла, то говорим что есть изменения
|
// если дополнительная проверка не прошла, то говорим что есть изменения
|
||||||
isChanged = true;
|
isChanged = true;
|
||||||
logger.LogDebug("Дополнительная проверка не прошла, ставим статус isChanged: {isChanged}", isChanged);
|
_logger.LogDebug("Дополнительная проверка не прошла, ставим статус isChanged: {isChanged}", isChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.LogDebug("Дополнительная проверка отсутствует");
|
_logger.LogDebug("Дополнительная проверка отсутствует");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isChanged)
|
if (isChanged)
|
||||||
{
|
{
|
||||||
logger.LogDebug("Есть изменения, требуется обновление. {TemplateName}", esppObject.TemplateName);
|
_logger.LogDebug("Есть изменения, требуется обновление. {TemplateName}", esppObject.TemplateName);
|
||||||
|
|
||||||
var config = robotConfigurationService.GetFromTemplateByRobotCode(esppObject.Robot, template);
|
var config = robotConfigurationService.GetFromTemplateByRobotCode(esppObject.Robot, template);
|
||||||
|
|
||||||
@@ -160,25 +178,25 @@ namespace PARR.EsppSync
|
|||||||
if (isChangedStatus)
|
if (isChangedStatus)
|
||||||
{
|
{
|
||||||
if (!await templateService.CommitAsync(GetInitiator()))
|
if (!await templateService.CommitAsync(GetInitiator()))
|
||||||
logger.LogError("Не удалось изменить запись Template {TemplateName}, Robot: {Robot}", template.Name, esppObject.Robot);
|
_logger.LogError("Не удалось изменить запись Template {TemplateName}, Robot: {Robot}", template.Name, esppObject.Robot);
|
||||||
else
|
else
|
||||||
logger.LogInformation("Установлен принудительный статус {TaskStatus}, Template {templateName}, Robot: {Robot}", TaskStatusEnum.Updating, template.Name, esppObject.Robot);
|
_logger.LogInformation("Установлен принудительный статус {TaskStatus}, Template {templateName}, Robot: {Robot}", TaskStatusEnum.Updating, template.Name, esppObject.Robot);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.LogInformation("Нельзя установить статус Updating для шаблона {templateName}, так как текущий статус это запрещает.", template.Name);
|
_logger.LogInformation("Нельзя установить статус Updating для шаблона {templateName}, так как текущий статус это запрещает.", template.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Если пред статус был Update, то ничего не делаем, так его и оставляем, не сбрасывам кол-во попыток и ошибок
|
// Если пред статус был Update, то ничего не делаем, так его и оставляем, не сбрасывам кол-во попыток и ошибок
|
||||||
logger.LogInformation("Есть изменения в Template {TemplateName}, но предыдущий статус TaskStatusCode: {TaskStatusCode}. Не меняем статус, будем разбираться вручную.", template.Name, (TaskStatusEnum)config.TaskStatusCode);
|
_logger.LogInformation("Есть изменения в Template {TemplateName}, но предыдущий статус TaskStatusCode: {TaskStatusCode}. Не меняем статус, будем разбираться вручную.", template.Name, (TaskStatusEnum)config.TaskStatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
}//надо ли проверять если не изменился, но был статус Updating не понятно. Доверяем роботу пока, что после окончания работ он точно сообщит
|
}//надо ли проверять если не изменился, но был статус Updating не понятно. Доверяем роботу пока, что после окончания работ он точно сообщит
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.LogDebug("Нет изменений, обновление не требуется. {TemplateName}", esppObject.TemplateName);
|
_logger.LogDebug("Нет изменений, обновление не требуется. {TemplateName}", esppObject.TemplateName);
|
||||||
|
|
||||||
//если все поля совпали
|
//если все поля совпали
|
||||||
//проверяем, какой был статус предыдущий статус в БД, если он был не Ок, то ставим ему ОК
|
//проверяем, какой был статус предыдущий статус в БД, если он был не Ок, то ставим ему ОК
|
||||||
@@ -187,15 +205,15 @@ namespace PARR.EsppSync
|
|||||||
{
|
{
|
||||||
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Ok, robotConfig);
|
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Ok, robotConfig);
|
||||||
if (!await templateService.CommitAsync(GetInitiator()))
|
if (!await templateService.CommitAsync(GetInitiator()))
|
||||||
logger.LogError("Не удалось изменить запись Template {TemplateName}, Robot: {Robot}", template.Name, esppObject.Robot);
|
_logger.LogError("Не удалось изменить запись Template {TemplateName}, Robot: {Robot}", template.Name, esppObject.Robot);
|
||||||
else
|
else
|
||||||
logger.LogInformation("Установлен принудительный статус {TaskStatus}, Template {TemplateName}, Robot: {Robot}", TaskStatusEnum.Ok, template.Name, esppObject.Robot);
|
_logger.LogInformation("Установлен принудительный статус {TaskStatus}, Template {TemplateName}, Robot: {Robot}", TaskStatusEnum.Ok, template.Name, esppObject.Robot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, "Ошибка синхронизации объекта АСУ ЕСПП {TemplateName}", esppObject.TemplateName);
|
_logger.LogError(ex, "Ошибка синхронизации объекта АСУ ЕСПП {TemplateName}, {EsppObject}", esppObject.TemplateName, nameof(EsppObject));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,36 +261,6 @@ namespace PARR.EsppSync
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// Установить статус - Обновить
|
|
||||||
///// </summary>
|
|
||||||
///// <param name="template"></param>
|
|
||||||
///// <param name="robotConfigurationService"></param>
|
|
||||||
///// <param name="robot"></param>
|
|
||||||
//private void SetUpdateStatus(ref Template template, IRobotConfigurationService robotConfigurationService, RobotsEnum robot)
|
|
||||||
//{
|
|
||||||
// var robotConfig = robotConfigurationService.GetFromTemplateByRobotCode(robot, template);
|
|
||||||
// robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, robotConfig);
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить сервис из scope
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="Service"></typeparam>
|
|
||||||
/// <param name="scope"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="Exception"></exception>
|
|
||||||
private Service GetServiceInScope<Service>(IServiceScope scope)
|
|
||||||
{
|
|
||||||
var service = scope.ServiceProvider.GetService<Service>();
|
|
||||||
if (service == null)
|
|
||||||
throw new Exception($"Не найден сервис: {nameof(Service)}");
|
|
||||||
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Сравнение объектов
|
/// Сравнение объектов
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -282,31 +270,35 @@ namespace PARR.EsppSync
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private bool IsChanged(object esppObj, object dbObj, string templateName)
|
private bool IsChanged(object esppObj, object dbObj, string templateName)
|
||||||
{
|
{
|
||||||
foreach (var prop in dbObj.GetType().GetProperties())
|
var dbType = dbObj.GetType();
|
||||||
|
var esppType = esppObj.GetType();
|
||||||
|
|
||||||
|
foreach (var dbProp in dbType.GetProperties())
|
||||||
{
|
{
|
||||||
// Пропускаем свойства, помеченные атрибутом SkipComparison
|
// Пропускаем свойства, помеченные атрибутом SkipComparison
|
||||||
if (Attribute.IsDefined(prop, typeof(SkipComparisonAttribute)))
|
if (Attribute.IsDefined(dbProp, typeof(SkipComparisonAttribute)))
|
||||||
{
|
{
|
||||||
logger.LogDebug("Пропущено сравнение поля {PropertyName} (помечено [SkipComparison]). Шаблон: {TemplateName}", prop.Name, templateName);
|
_logger.LogDebug("Пропущено сравнение поля {PropertyName} (помечено [SkipComparison]). Шаблон: {TemplateName}", dbProp.Name, templateName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prop == null)
|
// Значение из объекта БД
|
||||||
continue;
|
//var dbValue = dbObj.GetType().GetProperty(prop.Name)?.GetValue(dbObj, null);
|
||||||
|
var dbValue = dbProp.GetValue(dbObj);
|
||||||
|
|
||||||
var dbValue = dbObj.GetType().GetProperty(prop.Name)?.GetValue(dbObj, null);
|
// Ищем аналогичное свойство в объекте из ЕСПП по имени
|
||||||
var esppValue = esppObj.GetType().GetProperty(prop.Name)?.GetValue(esppObj, null);
|
//var esppValue = esppObj.GetType().GetProperty(dbProp.Name)?.GetValue(esppObj, null);
|
||||||
|
var esppProp = esppType.GetProperty(dbProp.Name);
|
||||||
|
var esppValue = esppProp?.GetValue(esppObj);
|
||||||
|
|
||||||
if (dbValue == null || esppValue == null)
|
// Replace("\r","").Replace("\n","") - в подробном описании могут быть переносы строк, в Rabbit прилетает без переносов. Убираем переносы для стравнения
|
||||||
continue;
|
// Если значение null, хелпер Normalize вернет string.Empty, что предотвратит NRE и ложные срабатывания.
|
||||||
|
var dbValueStr = EsppSyncHelpers.Normalize(dbValue?.ToString());
|
||||||
//Replace("\r","").Replace("\n","") - в подробном описании могут быть переносы строк, в Rabbit прилетает без переносов. Убираем переносы для стравнения
|
var esppValueStr = EsppSyncHelpers.Normalize(esppValue?.ToString());
|
||||||
var dbValueStr = EsppSyncHelpers.Normalize(dbValue!.ToString());
|
|
||||||
var esppValueStr = EsppSyncHelpers.Normalize(esppValue!.ToString());
|
|
||||||
|
|
||||||
if (dbValueStr != esppValueStr)
|
if (dbValueStr != esppValueStr)
|
||||||
{
|
{
|
||||||
logger.LogInformation("Не совпадают поля ({PropertyName}). dbValueStr: {DbValueStr}, esppValueStr: {EsppValueStr}. Имя шаблона: {TemplateName}", prop.Name, dbValueStr, esppValueStr, templateName);
|
_logger.LogInformation("Не совпадают поля ({PropertyName}). dbValueStr: {DbValueStr}, esppValueStr: {EsppValueStr}. Имя шаблона: {TemplateName}", dbProp.Name, dbValueStr, esppValueStr, templateName);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ using Microsoft.Extensions.Logging;
|
|||||||
using PARR.Core.Extensions;
|
using PARR.Core.Extensions;
|
||||||
using PARR.Core.Repositories.Interfaces;
|
using PARR.Core.Repositories.Interfaces;
|
||||||
using PARR.Core.Repositories.Interfaces.JobRepositories;
|
using PARR.Core.Repositories.Interfaces.JobRepositories;
|
||||||
|
using PARR.Core.Repositories.Interfaces.TemplateRepositories;
|
||||||
using PARR.Core.Repositories.Interfaces.Unit;
|
using PARR.Core.Repositories.Interfaces.Unit;
|
||||||
using PARR.Core.Services.NextRunServices;
|
using PARR.Core.Services.NextRunServices;
|
||||||
using PARR.Domain.Common.Rabbit.Messages.TemplateMatching;
|
using PARR.Domain.Common.Rabbit.Messages.TemplateMatching;
|
||||||
|
using PARR.Domain.Entities;
|
||||||
using PARR.Domain.Entities.JobEntities;
|
using PARR.Domain.Entities.JobEntities;
|
||||||
|
using PARR.Domain.Entities.TemplateEntities;
|
||||||
using PARR.Domain.Enums;
|
using PARR.Domain.Enums;
|
||||||
|
|
||||||
namespace PARR.TemplateUpdater.Services
|
namespace PARR.TemplateUpdater.Services
|
||||||
@@ -20,6 +23,7 @@ namespace PARR.TemplateUpdater.Services
|
|||||||
private readonly IRobotConfigurationRepository robotConfigurationService;
|
private readonly IRobotConfigurationRepository robotConfigurationService;
|
||||||
private readonly INextRunService nextRunService;
|
private readonly INextRunService nextRunService;
|
||||||
private readonly IUnitInValueRepository unitInValueService;
|
private readonly IUnitInValueRepository unitInValueService;
|
||||||
|
private readonly ITemplateRenamePendingRepository _templateRenamePendingRepository;
|
||||||
|
|
||||||
public TemplateUpdaterService(
|
public TemplateUpdaterService(
|
||||||
ILogger<TemplateUpdaterService> logger,
|
ILogger<TemplateUpdaterService> logger,
|
||||||
@@ -28,7 +32,8 @@ namespace PARR.TemplateUpdater.Services
|
|||||||
IUnitRepository unitService,
|
IUnitRepository unitService,
|
||||||
IRobotConfigurationRepository robotConfigurationService,
|
IRobotConfigurationRepository robotConfigurationService,
|
||||||
INextRunService nextRunService,
|
INextRunService nextRunService,
|
||||||
IUnitInValueRepository unitInValueService
|
IUnitInValueRepository unitInValueService,
|
||||||
|
ITemplateRenamePendingRepository templateRenamePendingRepository
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
@@ -38,6 +43,7 @@ namespace PARR.TemplateUpdater.Services
|
|||||||
this.robotConfigurationService = robotConfigurationService;
|
this.robotConfigurationService = robotConfigurationService;
|
||||||
this.nextRunService = nextRunService;
|
this.nextRunService = nextRunService;
|
||||||
this.unitInValueService = unitInValueService;
|
this.unitInValueService = unitInValueService;
|
||||||
|
_templateRenamePendingRepository = templateRenamePendingRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -53,7 +59,8 @@ namespace PARR.TemplateUpdater.Services
|
|||||||
var template = await templateService.Get()
|
var template = await templateService.Get()
|
||||||
.Include(t => t.RobotConfigurations)
|
.Include(t => t.RobotConfigurations)
|
||||||
.Include(t => t.UnitsInTemplate)
|
.Include(t => t.UnitsInTemplate)
|
||||||
.AsSplitQuery()
|
//.AsSplitQuery()
|
||||||
|
.AsSingleQuery()
|
||||||
.FirstOrDefaultAsync(t => t.Id == query.TemplateId);
|
.FirstOrDefaultAsync(t => t.Id == query.TemplateId);
|
||||||
if (template == null)
|
if (template == null)
|
||||||
{
|
{
|
||||||
@@ -64,9 +71,14 @@ namespace PARR.TemplateUpdater.Services
|
|||||||
var templateIsChanged = false;
|
var templateIsChanged = false;
|
||||||
var scheduleIsChanged = false;
|
var scheduleIsChanged = false;
|
||||||
|
|
||||||
if (template.Name != query.Name.Trim())
|
var trimmedNewName = query.Name.Trim();
|
||||||
|
if (template.Name != trimmedNewName)
|
||||||
{
|
{
|
||||||
template.Name = query.Name.Trim();
|
var prepareOldNameResult = await PrepareOldTemplateNameAsync(template.Name, trimmedNewName, template);
|
||||||
|
if (!prepareOldNameResult)
|
||||||
|
return;
|
||||||
|
|
||||||
|
template.Name = trimmedNewName;
|
||||||
templateIsChanged = true;
|
templateIsChanged = true;
|
||||||
scheduleIsChanged = true;
|
scheduleIsChanged = true;
|
||||||
}
|
}
|
||||||
@@ -276,5 +288,57 @@ namespace PARR.TemplateUpdater.Services
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавление записи в таблицу ожидания переименования
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="oldName"></param>
|
||||||
|
/// <param name="newName"></param>
|
||||||
|
/// <param name="template"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task<bool> PrepareOldTemplateNameAsync(string oldName, string newName, Template template)
|
||||||
|
{
|
||||||
|
// Проверяем, не запущено ли уже переименование для этого шаблона
|
||||||
|
var alreadyPending = await _templateRenamePendingRepository.Get()
|
||||||
|
.AsNoTracking()
|
||||||
|
.FirstOrDefaultAsync(t => t.TemplateId == template.Id);
|
||||||
|
|
||||||
|
if (alreadyPending != null)
|
||||||
|
{
|
||||||
|
logger.LogError("При попытке переименования шаблона {TemplateId}, из '{OldName}' в '{NewName}', " +
|
||||||
|
"произошла ошибка, этот шаблон уже находится в процессе переименования (старое имя {PendingName})", template.Id, oldName, newName, alreadyPending.OldName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Уникально ли имя в таблице ожидания переименования
|
||||||
|
var existPendingOldName = await _templateRenamePendingRepository.Get()
|
||||||
|
.AsNoTracking()
|
||||||
|
.FirstOrDefaultAsync(t => t.OldName == oldName);
|
||||||
|
|
||||||
|
if (existPendingOldName != null)
|
||||||
|
{
|
||||||
|
logger.LogError("При добавлении старого имени в таблицу ожидания для шаблона {TemplateId} обнаружен конфликт: " +
|
||||||
|
"имя '{ExistOldName}' уже зарезервировано другим процессом для шаблона {ExistTemplateId}",
|
||||||
|
template.Id, existPendingOldName.OldName, existPendingOldName.TemplateId);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Все нормально, добавляем запись в таблицу
|
||||||
|
var pendingRename = new TemplateRenamePending
|
||||||
|
{
|
||||||
|
TemplateId = template.Id,
|
||||||
|
DateCreated = DateTimeOffset.UtcNow,
|
||||||
|
OldName = oldName,
|
||||||
|
Template = template
|
||||||
|
};
|
||||||
|
|
||||||
|
var addResult = await _templateRenamePendingRepository.CreateAsync(pendingRename);
|
||||||
|
if (!addResult)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user