diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8cf56b03..bf8f2f97 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -17,6 +17,7 @@ variables:
PROD_TEMPLATE_TASK_GENERATOR: "parr/parr-template-task-generator"
PROD_JOB_AUTO_CONTROL: "parr/parr-job-auto-control"
PROD_TEMPLATE_MATCHER: "parr/parr-template-matcher"
+ PROD_TEMPLATE_UPDATER: "parr/parr-template-updater"
stages:
- build
@@ -788,7 +789,7 @@ prod_job_auto_control_build:
prod_job_auto_control_deploy:
stage: deploy
environment:
- name: parr-template-activator
+ name: parr-job-auto-control
only:
- /^jac[0-9]+\.[0-9]+\.[0-9]+$/
except:
@@ -837,7 +838,7 @@ prod_template_matcher_build:
prod_template_matcher_deploy:
stage: deploy
environment:
- name: parr-template-activator
+ name: parr-template-matcher
only:
- /^tm[0-9]+\.[0-9]+\.[0-9]+$/
except:
@@ -852,3 +853,51 @@ prod_template_matcher_deploy:
tags:
- ${RUNNER}
+
+
+### TEMPLATE UPDATER PROD ###
+prod_template_updater_build:
+ stage: build
+ only:
+ - /^tu[0-9]+\.[0-9]+\.[0-9]+$/
+ except:
+ - branches
+ services:
+ - name: docker:20.10.21-dind
+ command: [
+ "--insecure-registry=10.99.253.167:8090",
+ "--registry-mirror=http://10.99.253.167:8090",
+ "--insecure-registry=harbor.dvgd.rzd",
+ "--tls=false"
+ ]
+ variables:
+ DOCKER_HOST: tcp://docker:2375
+ DOCKER_DRIVER: overlay2
+ DOCKER_TLS_CERTDIR: ""
+ script:
+ - APP_VERSION=$(echo $CI_COMMIT_TAG | tr -d tu)
+ - IMAGE_VERSION=$(echo $CI_COMMIT_TAG | sed 's/tu/v/g')
+ - docker build -t $REPO/$PROD_TEMPLATE_UPDATER:$IMAGE_VERSION -t $REPO/$PROD_TEMPLATE_UPDATER:latest -t $PROD_TEMPLATE_UPDATER:$IMAGE_VERSION -t $PROD_TEMPLATE_UPDATER:latest --build-arg app_version=$APP_VERSION -f PARR.TemplateUpdaterWorker/Dockerfile .
+ - docker login -u $HARBOR_PUSH_USER -p $HARBOR_PUSH_PASS $REPO
+ - docker push --all-tags $REPO/$PROD_TEMPLATE_UPDATER
+ tags:
+ - docker
+
+
+prod_template_updater_deploy:
+ stage: deploy
+ environment:
+ name: parr-template-updater
+ only:
+ - /^tu[0-9]+\.[0-9]+\.[0-9]+$/
+ except:
+ - branches
+ script:
+ - IMAGE_VERSION=$(echo $CI_COMMIT_TAG | sed 's/tu/v/g')
+ - docker login -u $HARBOR_PULL_USER -p $HARBOR_PULL_PASS $REPO
+ - tag=$IMAGE_VERSION docker stack deploy -c docker-compose.template-updater.yml parr-template-updater --with-registry-auth
+ parallel:
+ matrix:
+ - RUNNER: shell-api-swarm-01
+ tags:
+ - ${RUNNER}
\ No newline at end of file
diff --git a/PARR.API.sln b/PARR.API.sln
index e1b3da1d..1b9bfec1 100644
--- a/PARR.API.sln
+++ b/PARR.API.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
-VisualStudioVersion = 18.0.11222.15 d18.0
+VisualStudioVersion = 18.0.11222.15
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PARR.API", "PARR.API\PARR.API.csproj", "{82C57299-DA04-4A99-9C04-614FDDCE7AA1}"
EndProject
@@ -102,6 +102,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.TemplateMatcherWorker"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.DAL.Tests", "PARR.DAL.Tests\PARR.DAL.Tests.csproj", "{D61A7AB6-D785-477A-95D1-FBED049D6CE2}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.TemplateUpdaterWorker", "PARR.TemplateUpdaterWorker\PARR.TemplateUpdaterWorker.csproj", "{27263750-9C80-4F9D-A550-B9D9C473B386}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.TemplateUpdater", "PARR.TemplateUpdater\PARR.TemplateUpdater.csproj", "{10905C04-A6E5-42BC-9804-8671D22C5D6E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -286,6 +290,14 @@ Global
{D61A7AB6-D785-477A-95D1-FBED049D6CE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D61A7AB6-D785-477A-95D1-FBED049D6CE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D61A7AB6-D785-477A-95D1-FBED049D6CE2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {27263750-9C80-4F9D-A550-B9D9C473B386}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {27263750-9C80-4F9D-A550-B9D9C473B386}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {27263750-9C80-4F9D-A550-B9D9C473B386}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {27263750-9C80-4F9D-A550-B9D9C473B386}.Release|Any CPU.Build.0 = Release|Any CPU
+ {10905C04-A6E5-42BC-9804-8671D22C5D6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {10905C04-A6E5-42BC-9804-8671D22C5D6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {10905C04-A6E5-42BC-9804-8671D22C5D6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {10905C04-A6E5-42BC-9804-8671D22C5D6E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/PARR.BLL/Domain/Mq/TemplateUpdaterMq.cs b/PARR.BLL/Domain/Mq/TemplateUpdaterMq.cs
index 9117067e..8c83ea01 100644
--- a/PARR.BLL/Domain/Mq/TemplateUpdaterMq.cs
+++ b/PARR.BLL/Domain/Mq/TemplateUpdaterMq.cs
@@ -25,6 +25,6 @@ namespace PARR.BLL.Domain.Mq
public TemplateStatusTypeEnum StatusTypeId { get; set; }
- public required IHistoryInitiator Initiator { get; set; }
+ public required HistoryInitiator Initiator { get; set; }
}
}
diff --git a/PARR.DAL/Contracts/TaskStatusEnum.cs b/PARR.DAL/Contracts/TaskStatusEnum.cs
index c5c64bb3..d33eea7b 100644
--- a/PARR.DAL/Contracts/TaskStatusEnum.cs
+++ b/PARR.DAL/Contracts/TaskStatusEnum.cs
@@ -5,8 +5,17 @@
///
public enum TaskStatusEnum
{
+ ///
+ /// Требуется создание объекта в ЕСПП
+ ///
Creating = 10,
+ ///
+ /// Требуется обновление объекта в ЕСПП
+ ///
Updating = 20,
+ ///
+ /// Нормальное состояние объекта в ЕСПП и ПАРР. Объект в ПАРР соответствует объекту в ЕСПП
+ ///
Ok = 30
}
}
diff --git a/PARR.TemplateUpdater/ITemplateUpdater.cs b/PARR.TemplateUpdater/ITemplateUpdater.cs
new file mode 100644
index 00000000..454c663e
--- /dev/null
+++ b/PARR.TemplateUpdater/ITemplateUpdater.cs
@@ -0,0 +1,8 @@
+namespace PARR.TemplateUpdater
+{
+ public interface ITemplateUpdater
+ {
+ Task StartAsync();
+ Task StopAsync();
+ }
+}
diff --git a/PARR.TemplateUpdater/PARR.TemplateUpdater.csproj b/PARR.TemplateUpdater/PARR.TemplateUpdater.csproj
new file mode 100644
index 00000000..21190861
--- /dev/null
+++ b/PARR.TemplateUpdater/PARR.TemplateUpdater.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/PARR.TemplateUpdater/Services/ITemplateUpdaterService.cs b/PARR.TemplateUpdater/Services/ITemplateUpdaterService.cs
new file mode 100644
index 00000000..e06e34bf
--- /dev/null
+++ b/PARR.TemplateUpdater/Services/ITemplateUpdaterService.cs
@@ -0,0 +1,9 @@
+using PARR.BLL.Domain.Mq;
+
+namespace PARR.TemplateUpdater.Services
+{
+ internal interface ITemplateUpdaterService
+ {
+ Task UpdateTemplateAsync(TemplateUpdaterMq query);
+ }
+}
diff --git a/PARR.TemplateUpdater/Services/TemplateUpdaterService.cs b/PARR.TemplateUpdater/Services/TemplateUpdaterService.cs
new file mode 100644
index 00000000..346167fd
--- /dev/null
+++ b/PARR.TemplateUpdater/Services/TemplateUpdaterService.cs
@@ -0,0 +1,173 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Logging;
+using PARR.BLL.Domain.Mq;
+using PARR.Constants;
+using PARR.DAL.Contracts;
+using PARR.DAL.Extensions;
+using PARR.DAL.Services.Interfaces;
+using PARR.DAL.Services.Interfaces.Job;
+using PARR.DAL.Services.Interfaces.Unit;
+
+namespace PARR.TemplateUpdater.Services
+{
+ internal class TemplateUpdaterService : ITemplateUpdaterService
+ {
+ private readonly ILogger logger;
+ private readonly ITemplateService templateService;
+ private readonly IJobService jobService;
+ private readonly IUnitService unitService;
+ private readonly IRobotConfigurationService robotConfigurationService;
+
+ public TemplateUpdaterService(
+ ILogger logger,
+ ITemplateService templateService,
+ IJobService jobService,
+ IUnitService unitService,
+ IRobotConfigurationService robotConfigurationService
+ )
+ {
+ this.logger = logger;
+ this.templateService = templateService;
+ this.jobService = jobService;
+ this.unitService = unitService;
+ this.robotConfigurationService = robotConfigurationService;
+ }
+
+
+ public async Task UpdateTemplateAsync(TemplateUpdaterMq query)
+ {
+ var isValid = await IsValidAsync(query);
+ if (!isValid)
+ {
+ logger.LogError($"Не валидны входные данные. Конец обработки сообщения {query.ToJson()}");
+ return;
+ }
+
+ var template = await templateService.Get()
+ .Include(t => t.RobotConfigurations)
+ .FirstOrDefaultAsync(t => t.Id == query.TemplateId);
+ if (template == null)
+ {
+ logger.LogError($"Не найден шаблон с id {query.TemplateId}");
+ return;
+ }
+
+ var templateIsChanged = false;
+ var scheduleIsChanged = false;
+
+ if (template.Name != query.Name.Trim())
+ {
+ template.Name = query.Name.Trim();
+ templateIsChanged = true;
+ scheduleIsChanged = true;
+ }
+
+ if (template.JobId != query.JobId)
+ {
+ template.JobId = query.JobId;
+ templateIsChanged = true;
+ scheduleIsChanged = true;
+ }
+
+ if (template.IsActiveTemplate != query.IsActiveTemplate)
+ {
+ template.IsActiveTemplate = query.IsActiveTemplate;
+ templateIsChanged = true;
+ }
+
+ if (template.IsActiveSchedule != query.IsActiveSchedule)
+ {
+ template.IsActiveSchedule = query.IsActiveSchedule;
+ scheduleIsChanged = true;
+ }
+
+ if (template.NextRun != query.NextRun)
+ {
+ template.NextRun = query.NextRun;
+ scheduleIsChanged = true;
+ }
+
+
+ if (template.UnitId != query.UnitId)
+ {
+ template.UnitId = query.UnitId;
+ templateIsChanged = true;
+ scheduleIsChanged = true;
+ }
+
+ //просто обнволяем. не влияет ни на шаблон, ни на расписание
+ template.LastRun = query.LastRun;
+ template.Index = query.Index;
+ template.StatusTypeId = query.StatusTypeId;
+
+ if (templateIsChanged)
+ {
+ // ставим задачу на обновление шаблона
+ var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.TemplateOrder, template);
+ robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, config);
+
+ logger.LogDebug($"Для шаблона {nameof(template.Id)}:{template.Id} устанавливаю статус {RobotStatusEnum.Wait.ToString()}");
+ }
+
+ if (scheduleIsChanged)
+ {
+ // ставим задачу на обновление расписания
+ var config = robotConfigurationService.GetFromTemplateByRobotCode(RobotsEnum.ScheduleOrder, template);
+ robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, config);
+
+ logger.LogDebug($"Для расписания {nameof(template.Id)}:{template.Id} устанавливаю статус {RobotStatusEnum.Wait.ToString()}");
+ }
+
+
+ if (!await templateService.CommitAsync(query.Initiator))
+ logger.LogError($"Не удалось сохранить изменения в БД. {nameof(TemplateUpdaterMq)}: {query.ToJson()}.");
+
+ logger.LogInformation($"Выполнено изменение шаблона в БД. Отправлен запрос на синхронизацию шаблона: {templateIsChanged}, расписания: {scheduleIsChanged} .Query {query.ToJson()}");
+ }
+
+
+ ///
+ /// Валидация входящего сообщения
+ ///
+ ///
+ ///
+ private async Task IsValidAsync(TemplateUpdaterMq query)
+ {
+ var template = await templateService.Get().AsNoTracking().AnyAsync(t => t.Id == query.TemplateId);
+ if (!template)
+ {
+ logger.LogError($"Сообщение не валидно. Не найден шаблон с id: {query.TemplateId}");
+ return false;
+ }
+
+ if (string.IsNullOrEmpty(query.Name.Trim()))
+ {
+ logger.LogError($"Сообщение не валидно. Имя шаблона не может быть пустым: {query.Name}");
+ return false;
+ }
+
+ var existTemplateName = await templateService.Get().AsNoTracking().AnyAsync(t => t.Id != query.TemplateId && t.Name.ToUpper() == query.Name.Trim().ToUpper());
+ if (existTemplateName)
+ {
+ logger.LogError($"Сообщение не валидно. Имя шаблона не уникально: {query.Name}");
+ return false;
+ }
+
+ var job = await jobService.Get().AsNoTracking().AnyAsync(t => t.Id == query.JobId);
+ if (!job)
+ {
+ logger.LogError($"Сообщение не валидно. Не найдена работа с JobId: {query.JobId}");
+ return false;
+ }
+
+ var unit = await unitService.Get().AsNoTracking().AnyAsync(t => t.Id == query.UnitId);
+ if (!unit)
+ {
+ logger.LogError($"Сообщение не валидно. Не найден unit с UnitId: {query.UnitId}");
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/PARR.TemplateUpdater/Settings/MqSettings.cs b/PARR.TemplateUpdater/Settings/MqSettings.cs
new file mode 100644
index 00000000..f611d854
--- /dev/null
+++ b/PARR.TemplateUpdater/Settings/MqSettings.cs
@@ -0,0 +1,18 @@
+using PARR.BLL.Contracts.Interfaces;
+
+namespace PARR.TemplateUpdater.Settings
+{
+ internal class MqSettings
+ {
+ public TemplatesUpdaterMq TemplatesUpdater { get; set; } = new TemplatesUpdaterMq();
+ }
+
+ internal class TemplatesUpdaterMq : IMqSettings
+ {
+ public string HostName { get; set; } = string.Empty;
+ public string QueueName { get; set; } = string.Empty;
+ public string User { get; set; } = string.Empty;
+ public string Password { get; set; } = string.Empty;
+ public ushort? PrefetchCount { get; set; } = 0;
+ }
+}
diff --git a/PARR.TemplateUpdater/TemplateUpdater.cs b/PARR.TemplateUpdater/TemplateUpdater.cs
new file mode 100644
index 00000000..257b78d8
--- /dev/null
+++ b/PARR.TemplateUpdater/TemplateUpdater.cs
@@ -0,0 +1,67 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using PARR.BLL.Domain.Mq;
+using PARR.BLL.Services.Interfaces;
+using PARR.TemplateUpdater.Services;
+using PARR.TemplateUpdater.Settings;
+
+namespace PARR.TemplateUpdater
+{
+ internal class TemplateUpdater : ITemplateUpdater
+ {
+ private readonly MqSettings mqSettings;
+ private readonly IMqService mqService;
+ private readonly ILogger logger;
+ private readonly IServiceProvider serviceProvider;
+ private readonly ITransformService transformService;
+
+ public TemplateUpdater(
+ MqSettings mqSettings,
+ IMqService mqService,
+ ILogger logger,
+ IServiceProvider serviceProvider,
+ ITransformService transformService
+ )
+ {
+ this.mqSettings = mqSettings;
+ this.mqService = mqService;
+ this.logger = logger;
+ this.serviceProvider = serviceProvider;
+ this.transformService = transformService;
+ }
+
+
+ public async Task StartAsync()
+ {
+ var isConnected = await mqService.InitConsumerAsync(mqSettings.TemplatesUpdater, UpdateTemplateAsync);
+
+ if (!isConnected)
+ throw new Exception("Ошибка при подключении к RabbitMq");
+ }
+
+
+ public async Task StopAsync()
+ {
+ await mqService.DisposeAsync();
+ }
+
+
+ private async Task UpdateTemplateAsync(string msg)
+ {
+ logger.LogInformation($"Получили запрос: {msg}");
+
+ var query = transformService.GetModelFromJson(msg);
+ if (query == null)
+ return;
+
+ using (var scope = serviceProvider.CreateScope())
+ {
+ var service = scope.ServiceProvider.GetService();
+ if (service == null)
+ throw new Exception($"Не найден сервис: {nameof(service.GetType)}");
+
+ await service.UpdateTemplateAsync(query);
+ }
+ }
+ }
+}
diff --git a/PARR.TemplateUpdater/TemplateUpdaterInstaller.cs b/PARR.TemplateUpdater/TemplateUpdaterInstaller.cs
new file mode 100644
index 00000000..8704d7a6
--- /dev/null
+++ b/PARR.TemplateUpdater/TemplateUpdaterInstaller.cs
@@ -0,0 +1,37 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using PARR.BLL;
+using PARR.DAL;
+using PARR.TemplateUpdater.Services;
+using PARR.TemplateUpdater.Settings;
+
+namespace PARR.TemplateUpdater
+{
+ public static class TemplateUpdaterInstaller
+ {
+ public static void InstallTemplateUpdaterServices(this IServiceCollection services, IConfiguration configuration)
+ {
+ services.InstallBllServices(configuration);
+ services.InstallDalServices(configuration);
+
+ var mqSettings = new MqSettings();
+ configuration.GetSection(nameof(MqSettings)).Bind(mqSettings);
+ services.AddSingleton(mqSettings);
+
+ services.AddTransient();
+ services.AddTransient();
+ }
+
+ public static IConfigurationBuilder AddTemplateUpdaterConfigurations(this IConfigurationBuilder builder, IServiceCollection services)
+ {
+ builder.AddDalConfigurations(services);
+
+ return builder;
+ }
+
+ public static void AddTemplateUpdaterSettings(this IServiceCollection services, IConfiguration configuration)
+ {
+ services.AddDallSettings(configuration);
+ }
+ }
+}
diff --git a/PARR.TemplateUpdaterWorker/Dockerfile b/PARR.TemplateUpdaterWorker/Dockerfile
new file mode 100644
index 00000000..635ad3ab
--- /dev/null
+++ b/PARR.TemplateUpdaterWorker/Dockerfile
@@ -0,0 +1,34 @@
+# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+# This stage is used when running from VS in fast mode (Default for Debug configuration)
+FROM 10.99.253.167:8090/dotnet/runtime:7.0 AS base
+WORKDIR /app
+
+
+# This stage is used to build the service project
+FROM 10.99.253.167:8090/dotnet/sdk:7.0 AS build
+ARG BUILD_CONFIGURATION=Release
+WORKDIR /src
+COPY ["NuGet.config", "."]
+COPY ["PARR.TemplateUpdaterWorker/PARR.TemplateUpdaterWorker.csproj", "PARR.TemplateUpdaterWorker/"]
+COPY ["PARR.TemplateUpdater/PARR.TemplateUpdater.csproj", "PARR.TemplateUpdater/"]
+COPY ["PARR.BLL/PARR.BLL.csproj", "PARR.BLL/"]
+COPY ["PARR.Common/PARR.Common.csproj", "PARR.Common/"]
+COPY ["PARR.Constants/PARR.Constants.csproj", "PARR.Constants/"]
+COPY ["PARR.DAL/PARR.DAL.csproj", "PARR.DAL/"]
+RUN dotnet restore "./PARR.TemplateUpdaterWorker/PARR.TemplateUpdaterWorker.csproj"
+COPY . .
+WORKDIR "/src/PARR.TemplateUpdaterWorker"
+RUN dotnet build "./PARR.TemplateUpdaterWorker.csproj" -c $BUILD_CONFIGURATION -o /app/build
+
+# This stage is used to publish the service project to be copied to the final stage
+FROM build AS publish
+ARG app_version=0.0.0-default
+ARG BUILD_CONFIGURATION=Release
+RUN dotnet publish "./PARR.TemplateUpdaterWorker.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false /p:Version=$app_version
+
+# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "PARR.TemplateUpdaterWorker.dll"]
\ No newline at end of file
diff --git a/PARR.TemplateUpdaterWorker/PARR.TemplateUpdaterWorker.csproj b/PARR.TemplateUpdaterWorker/PARR.TemplateUpdaterWorker.csproj
new file mode 100644
index 00000000..dd77a465
--- /dev/null
+++ b/PARR.TemplateUpdaterWorker/PARR.TemplateUpdaterWorker.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net7.0
+ enable
+ enable
+ dotnet-PARR.TemplateUpdaterWorker-413e055b-7f45-4b87-bbb3-28a3427d03f2
+ Linux
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PARR.TemplateUpdaterWorker/Program.cs b/PARR.TemplateUpdaterWorker/Program.cs
new file mode 100644
index 00000000..52a7cd2a
--- /dev/null
+++ b/PARR.TemplateUpdaterWorker/Program.cs
@@ -0,0 +1,31 @@
+using Elastic.CommonSchema.Serilog;
+using PARR.TemplateUpdater;
+using PARR.TemplateUpdaterWorker;
+using Serilog;
+
+var builder = Host.CreateApplicationBuilder();
+
+builder.Services.AddLogging(config =>
+{
+ config.ClearProviders();
+
+ var logger = new LoggerConfiguration();
+
+ if (builder.Environment.IsProduction())
+ logger.WriteTo.Console(new EcsTextFormatter());
+ else
+ logger.WriteTo.Console();
+
+ logger.ReadFrom.Configuration(builder.Configuration);
+
+ config.AddSerilog(logger.CreateLogger());
+});
+
+builder.Services.InstallTemplateUpdaterServices(builder.Configuration);
+builder.Configuration.AddTemplateUpdaterConfigurations(builder.Services);
+builder.Services.AddTemplateUpdaterSettings(builder.Configuration);
+
+builder.Services.AddHostedService();
+
+var host = builder.Build();
+host.Run();
diff --git a/PARR.TemplateUpdaterWorker/Properties/launchSettings.json b/PARR.TemplateUpdaterWorker/Properties/launchSettings.json
new file mode 100644
index 00000000..98e74de9
--- /dev/null
+++ b/PARR.TemplateUpdaterWorker/Properties/launchSettings.json
@@ -0,0 +1,14 @@
+{
+ "profiles": {
+ "PARR.TemplateUpdaterWorker": {
+ "commandName": "Project",
+ "environmentVariables": {
+ "DOTNET_ENVIRONMENT": "Development"
+ },
+ "dotnetRunMessages": true
+ },
+ "Container (Dockerfile)": {
+ "commandName": "Docker"
+ }
+ }
+}
\ No newline at end of file
diff --git a/PARR.TemplateUpdaterWorker/Worker.cs b/PARR.TemplateUpdaterWorker/Worker.cs
new file mode 100644
index 00000000..bda29c79
--- /dev/null
+++ b/PARR.TemplateUpdaterWorker/Worker.cs
@@ -0,0 +1,29 @@
+using PARR.TemplateUpdater;
+
+namespace PARR.TemplateUpdaterWorker
+{
+ public class Worker : BackgroundService
+ {
+ private readonly ILogger _logger;
+ private readonly ITemplateUpdater templateUpdater;
+
+ public Worker(ILogger logger, ITemplateUpdater templateUpdater)
+ {
+ _logger = logger;
+ this.templateUpdater = templateUpdater;
+ }
+
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ await templateUpdater.StartAsync();
+ await Task.Delay(Timeout.Infinite, stoppingToken);
+ }
+
+ public override async Task StopAsync(CancellationToken cancellationToken)
+ {
+ await templateUpdater.StopAsync();
+ await base.StopAsync(cancellationToken);
+ }
+
+ }
+}
diff --git a/PARR.TemplateUpdaterWorker/appsettings.Development.json b/PARR.TemplateUpdaterWorker/appsettings.Development.json
new file mode 100644
index 00000000..74618fc4
--- /dev/null
+++ b/PARR.TemplateUpdaterWorker/appsettings.Development.json
@@ -0,0 +1,31 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Debug",
+ "Microsoft.AspNetCore": "Debug"
+ }
+ },
+ "Serilog": {
+ "MinimumLevel": {
+ "Default": "Debug",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "WriteTo": [
+ {
+ "Name": "File",
+ "Args": {
+ "path": "log/log-.txt",
+ "rollingInterval": "Day"
+ }
+ }
+ ]
+ },
+ "MqSettings": {
+ "TemplatesUpdater": {
+ "HostName": "10.99.253.216"
+ }
+ }
+}
diff --git a/PARR.TemplateUpdaterWorker/appsettings.json b/PARR.TemplateUpdaterWorker/appsettings.json
new file mode 100644
index 00000000..e2addf2c
--- /dev/null
+++ b/PARR.TemplateUpdaterWorker/appsettings.json
@@ -0,0 +1,28 @@
+{
+ "ConnectionStrings": {
+ "DefaultConnection": "Server=10.99.253.184;Database=parr;User Id=app_parr; Password=PosdfkhT&)%sdfligL&%5546;"
+ },
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "Serilog": {
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+ },
+ "MqSettings": {
+ "TemplatesUpdater": {
+ "HostName": "parr-rabbitmq",
+ "QueueName": "parr-template-updater",
+ "User": "template_updater_reader",
+ "Password": "JfdsfUFJJh2255&*&F1"
+ }
+ }
+}
diff --git a/README.md b/README.md
index 5118f964..32396903 100644
--- a/README.md
+++ b/README.md
@@ -43,4 +43,8 @@
- PARR.TemplateActivatorWorker
- PARR.TemplateDistributor - автораспределение РР
- PARR.TemplateDistributorWorker
+- PARR.TemplateMatcher
+- PARR.TemplateMatcherWorker
+- PARR.TemplateUpdater - обновление шаблонов
+- PARR.TemplateUpdaterWorker
- PARR.Test - тестирование функций ПАРР
diff --git a/docker-compose.template-updater.yml b/docker-compose.template-updater.yml
new file mode 100644
index 00000000..b3157eec
--- /dev/null
+++ b/docker-compose.template-updater.yml
@@ -0,0 +1,27 @@
+version: '3.4'
+
+#PARR TEMPLATE UPDATER
+services:
+ parr-template-updater:
+ image: harbor.dvgd.rzd/parr/parr-template-updater:${tag-latest}
+ environment:
+ - ASPNETCORE_ENVIRONMENT=Production
+ - TZ=Europe/Moscow
+ logging:
+ driver: fluentd
+ options:
+ fluentd-address: dvgd-efk-01.dvgd.oao.rzd:24224
+ fluentd-retry-wait: '10s'
+ fluentd-max-retries: '30'
+ fluentd-async: 'true'
+ fluentd-buffer-limit: '52428800'
+ tag: parr.template-updater.serilog
+ deploy:
+ replicas: 4
+ networks:
+ parr-network:
+
+networks:
+ parr-network:
+ driver: overlay
+ external: true
\ No newline at end of file