feat(api,core,dal,domain): Сохранение снапшотов состояния роботов.
This commit is contained in:
@@ -256,6 +256,11 @@
|
||||
public const string GetStatusesLastDay = BaseStat + "/orders/statuses/last-day/{statusCode}";
|
||||
}
|
||||
|
||||
public static class StatRobotSnapshot
|
||||
{
|
||||
public const string Create = BaseStat + "/robot-snapshots/";
|
||||
}
|
||||
|
||||
public static class StatRabbitMq
|
||||
{
|
||||
public const string GetQueueStats = BaseStat + "/rabbitmq-queues/";
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace PARR.API.Contracts.V1.Requests
|
||||
{
|
||||
public record StatRobotSnapshotCreateRequest
|
||||
{
|
||||
public int TemplateRobotsCount { get; set; }
|
||||
|
||||
public int ScheduleRobotsCount { get; set; }
|
||||
|
||||
public int MaxRobots { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace PARR.API.Contracts.V1.Responses.Statistics
|
||||
{
|
||||
public record StatRobotSnapshotItemResponse
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
|
||||
public DateTimeOffset DateCreated { get; init; }
|
||||
|
||||
public int TemplateRobotsCount { get; init; }
|
||||
|
||||
public int ScheduleRobotsCount { get; init; }
|
||||
|
||||
public int MaxRobots { get; init; }
|
||||
|
||||
public required string Ip { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PARR.API.Contracts.V1;
|
||||
using PARR.API.Contracts.V1.Requests;
|
||||
using PARR.API.Contracts.V1.Responses.Base;
|
||||
using PARR.API.Contracts.V1.Responses.Statistics;
|
||||
using PARR.API.Controllers.V1.Base;
|
||||
using PARR.API.Services.Interfaces;
|
||||
using PARR.Core.Services.RobotSnapshotServices;
|
||||
using PARR.Domain.Common.Roles;
|
||||
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||
|
||||
namespace PARR.API.Controllers.V1.Statistics
|
||||
{
|
||||
[Authorize(Roles = ParrRoles.Administrator.Role)]
|
||||
public class StatRobotSnapshotController : BaseApiController
|
||||
{
|
||||
private readonly IRobotSnapshotService robotSnapshotService;
|
||||
private readonly IMapper mapper;
|
||||
private readonly IClientService clientService;
|
||||
|
||||
public StatRobotSnapshotController(
|
||||
IRobotSnapshotService robotSnapshotService,
|
||||
IMapper mapper,
|
||||
IClientService clientService
|
||||
)
|
||||
{
|
||||
this.robotSnapshotService = robotSnapshotService;
|
||||
this.mapper = mapper;
|
||||
this.clientService = clientService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отправить снапшот роботов.
|
||||
/// Доступ только с ролью "Робот ЕСПП"
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[Authorize(Roles = ParrRoles.EsppRobot.Role)]
|
||||
[HttpPost(ApiRoutes.StatRobotSnapshot.Create)]
|
||||
public async Task<IActionResult> Create([FromBody] StatRobotSnapshotCreateRequest request)
|
||||
{
|
||||
var obj = new CreateRobotSnapshot(request.TemplateRobotsCount, request.ScheduleRobotsCount, request.MaxRobots, clientService.GetClientIp()?.ToString() ?? "");
|
||||
|
||||
var snapshot = await robotSnapshotService.CreateAsync(obj);
|
||||
|
||||
return Created("", new Response<StatRobotSnapshotItemResponse>(mapper.Map<StatRobotSnapshotItemResponse>(snapshot), true));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using PARR.API.Contracts.V1.Responses.Statistics;
|
||||
using PARR.API.MappingProfiles.Resolvers;
|
||||
using PARR.Core.Repositories.Interfaces.Schedule;
|
||||
using PARR.Domain.DTOs.Matching;
|
||||
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||
using PARR.Domain.DTOs.RobotTask;
|
||||
using PARR.Domain.DTOs.Shortcode;
|
||||
using PARR.Domain.DTOs.TaskDTO;
|
||||
@@ -485,6 +486,9 @@ namespace PARR.API.MappingProfiles
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
CreateMap<RobotSnapshotItem, StatRobotSnapshotItemResponse>();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using FluentValidation;
|
||||
using PARR.API.Contracts.V1.Requests;
|
||||
|
||||
namespace PARR.API.Validators
|
||||
{
|
||||
public class StatRobotSnapshotCreateRequestValidator: AbstractValidator<StatRobotSnapshotCreateRequest>
|
||||
{
|
||||
public StatRobotSnapshotCreateRequestValidator()
|
||||
{
|
||||
RuleFor(t => t.TemplateRobotsCount)
|
||||
.GreaterThanOrEqualTo(0)
|
||||
.WithMessage("Значение должно быть больше или равно нулю");
|
||||
|
||||
RuleFor(t => t.ScheduleRobotsCount)
|
||||
.GreaterThanOrEqualTo(0)
|
||||
.WithMessage("Значение должно быть больше или равно нулю");
|
||||
|
||||
RuleFor(t => t.MaxRobots)
|
||||
.GreaterThanOrEqualTo(0)
|
||||
.WithMessage("Значение должно быть больше или равно нулю");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using PARR.Core.Common.Interfaces;
|
||||
using PARR.Core.Services.MatchingStatusService;
|
||||
using PARR.Core.Services.NextRunServices;
|
||||
using PARR.Core.Services.NextRunServices.Subservices;
|
||||
using PARR.Core.Services.RobotSnapshotServices;
|
||||
using PARR.Core.Services.RobotTask.Implementations;
|
||||
using PARR.Core.Services.RobotTask.Interfaces;
|
||||
using PARR.Core.Services.Shortcodes;
|
||||
@@ -105,6 +106,7 @@ namespace PARR.Core
|
||||
services.AddTransient<IMatchingStatusService, MatchingStatusService>();
|
||||
|
||||
services.AddScoped<IRobotTaskService, RobotTaskService>();
|
||||
services.AddScoped<IRobotSnapshotService, RobotSnapshotService>();
|
||||
|
||||
services.AddScoped<IUnitService, UnitService>();
|
||||
services.AddScoped<UnitCacheService>();
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using AutoMapper;
|
||||
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||
|
||||
namespace PARR.Core.Infrastructure.Mapping.RobotSnapshot
|
||||
{
|
||||
public class RobotSnapshotMappingProfile : Profile
|
||||
{
|
||||
public RobotSnapshotMappingProfile()
|
||||
{
|
||||
CreateMap<PARR.Domain.Entities.RobotEntities.RobotSnapshot, RobotSnapshotItem>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using PARR.Core.Repositories.Base;
|
||||
using PARR.Domain.Entities.RobotEntities;
|
||||
|
||||
namespace PARR.Core.Repositories.Interfaces.RobotRepositories
|
||||
{
|
||||
public interface IRobotSnapshotRepository : IBaseRepository<RobotSnapshot>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||
|
||||
namespace PARR.Core.Services.RobotSnapshotServices
|
||||
{
|
||||
public interface IRobotSnapshotService
|
||||
{
|
||||
Task<RobotSnapshotItem> CreateAsync(CreateRobotSnapshot robotSnapshot);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using AutoMapper;
|
||||
using PARR.Core.Repositories.Interfaces.RobotRepositories;
|
||||
using PARR.Domain.DTOs.RobotSnapshotDTO;
|
||||
using PARR.Domain.Entities.RobotEntities;
|
||||
using PARR.Domain.Exceptions;
|
||||
|
||||
namespace PARR.Core.Services.RobotSnapshotServices
|
||||
{
|
||||
internal class RobotSnapshotService : IRobotSnapshotService
|
||||
{
|
||||
private readonly IRobotSnapshotRepository robotSnapshotRepository;
|
||||
private readonly IMapper mapper;
|
||||
|
||||
public RobotSnapshotService(
|
||||
IRobotSnapshotRepository robotSnapshotRepository,
|
||||
IMapper mapper
|
||||
)
|
||||
{
|
||||
this.robotSnapshotRepository = robotSnapshotRepository;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
|
||||
public async Task<RobotSnapshotItem> CreateAsync(CreateRobotSnapshot robotSnapshot)
|
||||
{
|
||||
var snapshot = new RobotSnapshot
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TemplateRobotsCount = robotSnapshot.TemplateRobotsCount,
|
||||
ScheduleRobotsCount = robotSnapshot.ScheduleRobotsCount,
|
||||
MaxRobots = robotSnapshot.MaxRobots,
|
||||
Ip = robotSnapshot.Ip
|
||||
};
|
||||
|
||||
var createdResult = await robotSnapshotRepository.CreateAsync(snapshot);
|
||||
var commitResult = await robotSnapshotRepository.CommitAsync();
|
||||
|
||||
if (!createdResult || !commitResult)
|
||||
throw new DbErrorException("Ошибка сохранения в БД");
|
||||
|
||||
return mapper.Map<RobotSnapshotItem>(snapshot);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using PARR.Domain.Common.Roles;
|
||||
using PARR.Domain.Common.Template;
|
||||
using PARR.Domain.Entities;
|
||||
using PARR.Domain.Entities.Job;
|
||||
using PARR.Domain.Entities.RobotEntities;
|
||||
using PARR.Domain.Entities.Schedule;
|
||||
using PARR.Domain.Entities.TaskEntities;
|
||||
using PARR.Domain.Entities.Unit;
|
||||
@@ -126,6 +127,12 @@ namespace PARR.DAL.Context
|
||||
|
||||
#endregion
|
||||
|
||||
#region Robot
|
||||
|
||||
public DbSet<RobotSnapshot> RobotSnapshots { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PARR.Core.Repositories.Interfaces;
|
||||
using PARR.Core.Repositories.Interfaces.Job;
|
||||
using PARR.Core.Repositories.Interfaces.RobotRepositories;
|
||||
using PARR.Core.Repositories.Interfaces.Schedule;
|
||||
using PARR.Core.Repositories.Interfaces.TaskRepositories;
|
||||
using PARR.Core.Repositories.Interfaces.Unit;
|
||||
@@ -11,6 +12,7 @@ using PARR.DAL.Configurations.DbSettings;
|
||||
using PARR.DAL.Context;
|
||||
using PARR.DAL.Repositories;
|
||||
using PARR.DAL.Repositories.Job;
|
||||
using PARR.DAL.Repositories.RobotRepositories;
|
||||
using PARR.DAL.Repositories.Schedule;
|
||||
using PARR.DAL.Repositories.TaskRepositories;
|
||||
using PARR.DAL.Repositories.Unit;
|
||||
@@ -79,6 +81,9 @@ namespace PARR.DAL
|
||||
services.AddTransient<IParrComponentRepository, ParrComponentRepository>();
|
||||
services.AddTransient<ITemplateStatusTypeRepository, TemplateStatusTypeRepository>();
|
||||
|
||||
services.AddScoped<IRobotSnapshotRepository, RobotSnapshotRepository>();
|
||||
|
||||
|
||||
#region Schedule
|
||||
|
||||
services.AddTransient<IScheduleExcludeTypeRepository, ScheduleExcludeTypeRepository>();
|
||||
|
||||
3809
PARR.DAL/Migrations/20260610042457_tblRobotSnapshot.Designer.cs
generated
Normal file
3809
PARR.DAL/Migrations/20260610042457_tblRobotSnapshot.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
64
PARR.DAL/Migrations/20260610042457_tblRobotSnapshot.cs
Normal file
64
PARR.DAL/Migrations/20260610042457_tblRobotSnapshot.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace PARR.DAL.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class tblRobotSnapshot : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.EnsureSchema(
|
||||
name: "robot");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Snapshots",
|
||||
schema: "robot",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
DateCreated = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||
TemplateRobotsCount = table.Column<int>(type: "integer", nullable: false, comment: "Количество запущенных роботов по шаблонам"),
|
||||
ScheduleRobotsCount = table.Column<int>(type: "integer", nullable: false, comment: "Количество запущенных роботов по расписаниям"),
|
||||
MaxRobots = table.Column<int>(type: "integer", nullable: false, comment: "Максимально разрешенное количество роботов на сервере"),
|
||||
Ip = table.Column<string>(type: "character varying(45)", maxLength: 45, nullable: false, comment: "Текущий IP-адрес сервера")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Snapshots", x => x.Id);
|
||||
},
|
||||
comment: "Снимки роботов");
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "Settings",
|
||||
keyColumn: "Name",
|
||||
keyValue: "RobotWaitTime",
|
||||
column: "Value",
|
||||
value: "00:10:00");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Snapshots_Ip_DateCreated",
|
||||
schema: "robot",
|
||||
table: "Snapshots",
|
||||
columns: new[] { "Ip", "DateCreated" });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Snapshots",
|
||||
schema: "robot");
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "Settings",
|
||||
keyColumn: "Name",
|
||||
keyValue: "RobotWaitTime",
|
||||
column: "Value",
|
||||
value: "00:15:00");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -867,6 +867,43 @@ namespace PARR.DAL.Migrations
|
||||
b.ToTable("RobotConfigurations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PARR.Domain.Entities.RobotEntities.RobotSnapshot", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTimeOffset>("DateCreated")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Ip")
|
||||
.IsRequired()
|
||||
.HasMaxLength(45)
|
||||
.HasColumnType("character varying(45)")
|
||||
.HasComment("Текущий IP-адрес сервера");
|
||||
|
||||
b.Property<int>("MaxRobots")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Максимально разрешенное количество роботов на сервере");
|
||||
|
||||
b.Property<int>("ScheduleRobotsCount")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Количество запущенных роботов по расписаниям");
|
||||
|
||||
b.Property<int>("TemplateRobotsCount")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("Количество запущенных роботов по шаблонам");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Ip", "DateCreated");
|
||||
|
||||
b.ToTable("Snapshots", "robot", t =>
|
||||
{
|
||||
t.HasComment("Снимки роботов");
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PARR.Domain.Entities.RobotHistory", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -2261,7 +2298,7 @@ namespace PARR.DAL.Migrations
|
||||
{
|
||||
Name = "RobotWaitTime",
|
||||
Description = "Время ожидания выполнения роботом задания",
|
||||
Value = "00:15:00"
|
||||
Value = "00:10:00"
|
||||
},
|
||||
new
|
||||
{
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using PARR.Core.Repositories.Interfaces.RobotRepositories;
|
||||
using PARR.DAL.Context;
|
||||
using PARR.DAL.Repositories.Base;
|
||||
using PARR.Domain.Entities.RobotEntities;
|
||||
|
||||
namespace PARR.DAL.Repositories.RobotRepositories
|
||||
{
|
||||
internal class RobotSnapshotRepository : BaseRepository<RobotSnapshot>, IRobotSnapshotRepository
|
||||
{
|
||||
public RobotSnapshotRepository(ILogger<RobotSnapshotRepository> logger, DataContext dataContext) : base(logger, dataContext) { }
|
||||
}
|
||||
}
|
||||
@@ -27,5 +27,11 @@
|
||||
/// Управление очередями
|
||||
/// </summary>
|
||||
public const string Task = "task";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Робот
|
||||
/// </summary>
|
||||
public const string Robot = "robot";
|
||||
}
|
||||
}
|
||||
|
||||
5
PARR.Domain/DTOs/RobotSnapshotDTO/CreateRobotSnapshot.cs
Normal file
5
PARR.Domain/DTOs/RobotSnapshotDTO/CreateRobotSnapshot.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
||||
{
|
||||
public record CreateRobotSnapshot(int TemplateRobotsCount, int ScheduleRobotsCount, int MaxRobots, string Ip);
|
||||
|
||||
}
|
||||
17
PARR.Domain/DTOs/RobotSnapshotDTO/RobotSnapshotItem.cs
Normal file
17
PARR.Domain/DTOs/RobotSnapshotDTO/RobotSnapshotItem.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace PARR.Domain.DTOs.RobotSnapshotDTO
|
||||
{
|
||||
public record RobotSnapshotItem
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
|
||||
public DateTimeOffset DateCreated { get; init; }
|
||||
|
||||
public int TemplateRobotsCount { get; init; }
|
||||
|
||||
public int ScheduleRobotsCount { get; init; }
|
||||
|
||||
public int MaxRobots { get; init; }
|
||||
|
||||
public required string Ip { get; init; }
|
||||
}
|
||||
}
|
||||
38
PARR.Domain/Entities/RobotEntities/RobotSnapshot.cs
Normal file
38
PARR.Domain/Entities/RobotEntities/RobotSnapshot.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PARR.Domain.Constants;
|
||||
using PARR.Domain.Entities.Base;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace PARR.Domain.Entities.RobotEntities
|
||||
{
|
||||
/// <summary>
|
||||
/// Снимок роботов с одного сервера
|
||||
/// </summary>
|
||||
[Table("Snapshots", Schema = DatabaseSchemas.Robot)]
|
||||
[Index(nameof(Ip), nameof(DateCreated))]
|
||||
[Comment("Снимки роботов")]
|
||||
public class RobotSnapshot : IBaseEntity
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public DateTimeOffset DateCreated { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public DateTimeOffset? DateModified { get; set; }
|
||||
|
||||
[Comment("Количество запущенных роботов по шаблонам")]
|
||||
public int TemplateRobotsCount { get; set; }
|
||||
|
||||
[Comment("Количество запущенных роботов по расписаниям")]
|
||||
public int ScheduleRobotsCount { get; set; }
|
||||
|
||||
[Comment("Максимально разрешенное количество роботов на сервере")]
|
||||
public int MaxRobots { get; set; }
|
||||
|
||||
[MaxLength(45)]
|
||||
[Comment("Текущий IP-адрес сервера")]
|
||||
public required string Ip { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -23,5 +23,6 @@
|
||||
<ProjectReference Include="..\PARR.EsppApi\PARR.EsppApi.csproj" />
|
||||
<ProjectReference Include="..\PARR.Infrastructure\PARR.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\PARR.TemplateDistributor\PARR.TemplateDistributor.csproj" />
|
||||
<ProjectReference Include="..\PARR.TemplateMatcher\PARR.TemplateMatcher.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user