feat(bll, all): обновлена библиотека RabbitMq.Client до версии 7.1.2. Обновлен MqServiceV2. В IMqSettings добавлен параметр PrefetchCount - макс кол-во одновременных обработок очередей. Обновлены связанные проекты под новый MqService. В проектах Aihit, SyncTemplate, SyncSchedule установлен параметр в конфиг PrefetchCount =100

This commit is contained in:
Mikhail Trubnikov
2025-08-20 14:10:22 +10:00
parent cdd11cdb4d
commit 85798c0956
58 changed files with 621 additions and 341 deletions

View File

@@ -64,7 +64,7 @@ namespace PARR.AIHITLoader
for (var i = 0; i < parts; i++)
{
var batch = preparedData.Skip(i * loaderSettings.PackageSize).Take(loaderSettings.PackageSize).ToList();
var sendResult = mqService.Send(mqSettings, batch.ToArray());
var sendResult = await mqService.SendAsync(mqSettings, batch.ToArray());
if (sendResult.IsSuccess)
{
logger.LogInformation($"Данные переданы в RabbitMQ: {batch.Count()}");
@@ -75,7 +75,7 @@ namespace PARR.AIHITLoader
}
}
await Task.CompletedTask;
// await Task.CompletedTask;
}
/// <summary>

View File

@@ -8,5 +8,6 @@ namespace PARR.AIHITLoader.Settings
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;
}
}

View File

@@ -77,7 +77,7 @@ namespace PARR.AIHITMainLoader
for (var i = 0; i < parts; i++)
{
var batch = preparedData.Skip(i * loaderSettings.PackageSize).Take(loaderSettings.PackageSize).ToList();
var sendResult = mqService.Send(mqSettings, batch.ToArray());
var sendResult = await mqService.SendAsync(mqSettings, batch.ToArray());
if (sendResult.IsSuccess)
{
logger.LogInformation($"Данные переданы в RabbitMQ: {batch.Count()}");
@@ -87,7 +87,7 @@ namespace PARR.AIHITMainLoader
logger.LogError($"Ошибка при передаче данных в Rabbit, не переданные сообщения: {string.Join(", ", sendResult.NotSendMessages!)}");
}
await Task.CompletedTask;
// await Task.CompletedTask;
}

View File

@@ -11,5 +11,7 @@ namespace PARR.AIHITMainLoader.Settings
public string User { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public ushort? PrefetchCount { get; set; } = 0;
}
}

View File

@@ -25,11 +25,11 @@ namespace PARR.AIHITMainSyncer
this.mqSettings = mqSettings;
this.serviceProvider = serviceProvider;
}
public void Start()
public async Task StartAsync()
{
logger.LogInformation("Запуск сервиса синхронизации данных из АИХИТ и ПАРР.");
var isConnected = mqService.InitConsumer(mqSettings, async (string msg) =>
var isConnected = await mqService.InitConsumerAsync(mqSettings, async (string msg) =>
{
using (var scope = serviceProvider.CreateScope())
{
@@ -47,9 +47,9 @@ namespace PARR.AIHITMainSyncer
}
public void Stop()
public async Task StopAsync()
{
mqService.Dispose();
await mqService.DisposeAsync();
}
}
}

View File

@@ -2,9 +2,8 @@
{
public interface IAihitMainSyncer
{
void Start();
Task StartAsync();
void Stop();
Task StopAsync();
}
}

View File

@@ -11,5 +11,7 @@ namespace PARR.AIHITMainSyncer.Settings
public string User { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public ushort? PrefetchCount { get; set; } = 0;
}
}

View File

@@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging;
using PARR.AIHITSyncer.Services;
using PARR.AIHITSyncer.Settings;
using PARR.BLL.Services.Interfaces;
using System.Threading.Tasks;
namespace PARR.AIHITSyncer
{
@@ -27,12 +28,12 @@ namespace PARR.AIHITSyncer
this.serviceProvider = serviceProvider;
}
public void Start()
public async Task StartAsync()
{
logger.LogInformation("Запуск сервиса синхронизации данных из АИХИТ и ПАРР.");
//var isConnected = mqService.InitConsumer(mqSettings, SyncDataAsync);
var isConnected = mqService.InitConsumer(mqSettings, async (string msg) =>
var isConnected = await mqService.InitConsumerAsync(mqSettings, async (string msg) =>
{
using (var scope = serviceProvider.CreateScope())
{
@@ -48,9 +49,9 @@ namespace PARR.AIHITSyncer
if (!isConnected)
throw new Exception("Ошибка при подключении к RabbitMq");
}
public void Stop()
public async Task StopAsync()
{
mqService.Dispose();
await mqService.DisposeAsync();
}
}

View File

@@ -2,7 +2,7 @@
{
public interface IAihitSyncer
{
void Start();
void Stop();
Task StartAsync();
Task StopAsync();
}
}

View File

@@ -8,5 +8,6 @@ namespace PARR.AIHITSyncer.Settings
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;
}
}

View File

@@ -16,13 +16,13 @@ namespace PARR.AIHITSyncerWorker
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
aihitSyncer.Start();
await aihitSyncer.StartAsync();
}
public override Task StopAsync(CancellationToken cancellationToken)
{
aihitSyncer.Stop();
aihitSyncer.StopAsync().Wait();
return base.StopAsync(cancellationToken);
}

View File

@@ -33,6 +33,7 @@
"HostName": "10.99.253.216",
"QueueName": "parr-aihit-data",
"User": "aihit_syncer",
"Password": "afsdgDGjhfiU76496as42!@"
"Password": "afsdgDGjhfiU76496as42!@",
"PrefetchCount": 100
}
}

View File

@@ -53,7 +53,7 @@ namespace PARR.API.Controllers.V1
var msg = JsonSerializer.Serialize(requestToMq);
var sendResult = mqService.Send(mqSettings.TemplateDistributor, new[] { msg });
var sendResult = await mqService.SendAsync(mqSettings.TemplateDistributor, new[] { msg });
if (sendResult.IsSuccess)
return Created("", new Response<string?>(null, true, new List<ErrorModel>(), "Отправлен запрос на перераспределение регламентных работ."));

View File

@@ -54,7 +54,8 @@ namespace PARR.API.Controllers.V1
request.Ek.ForEach(ek =>
{
request.Status.ForEach(status =>
//todo: проверить в ForEach(async status - отрабатывает ли нормально async, возможно надо переделать в обычный foreach
request.Status.ForEach(async status =>
{
var obj = new GeneratorTemplateMq
{
@@ -70,7 +71,7 @@ namespace PARR.API.Controllers.V1
var msg = JsonSerializer.Serialize(obj);
var _result = mqService.Send(mqSettings.GenerateTemplates, new[] { msg });
var _result = await mqService.SendAsync(mqSettings.GenerateTemplates, new[] { msg });
if (_result.IsSuccess == false)
result = false;

View File

@@ -74,7 +74,7 @@ namespace PARR.API.Controllers.V1
var msg = JsonSerializer.Serialize(mqRequest);
var sendResult = mqService.Send(mqSettings.TemplateActivator, new[] { msg });
var sendResult = await mqService.SendAsync(mqSettings.TemplateActivator, new[] { msg });
if (!sendResult.IsSuccess)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при отправке данных." } }));

View File

@@ -26,7 +26,6 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="RabbitMQ.Client" Version="6.5.0" />
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />

View File

@@ -16,6 +16,7 @@ namespace PARR.API.Settings
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;
}
public class MqTemplateDistributor : IMqSettings
@@ -24,6 +25,7 @@ namespace PARR.API.Settings
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;
}
public class MqTemplateActivator : IMqSettings
@@ -32,6 +34,7 @@ namespace PARR.API.Settings
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;
}
public class MqStatistics
@@ -45,5 +48,6 @@ namespace PARR.API.Settings
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;
}
}

View File

@@ -9,5 +9,9 @@
string QueueName { get; set; }
string User { get; set; }
string Password { get; set; }
/// <summary>
/// Кол-во сообщений которые может принимать consumer за один раз. 0 или null - без ограничений
/// </summary>
ushort? PrefetchCount { get; set; }
}
}

View File

@@ -12,7 +12,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="RabbitMQ.Client" Version="6.5.0" />
<PackageReference Include="RabbitMQ.Client" Version="7.1.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -17,7 +17,10 @@ namespace PARR.BLL
services.AddTransient<IFileService, FileService>();
services.AddTransient<IMqService, MqService>();
//services.AddTransient<IMqService, MqService>();
services.AddTransient<IMqService, MqServiceV2>();
services.AddHttpClient<IMqAdminService, MqAdminService>();
services.AddTransient<ITransformService, TransformService>();
services.AddTransient<IIntervalService, IntervalService>();

View File

@@ -4,18 +4,19 @@ using PARR.BLL.Domain.Mq;
using PARR.BLL.Services.Interfaces;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Runtime;
using System.Text;
namespace PARR.BLL.Services.Implementations
{
internal class MqService : IMqService
// RabbitMqClient 6.5.0
internal class MqService// : IMqService
{
private readonly ILogger<MqService> logger;
private IConnection? connection;
private IModel? channel;
//private IModel? channel;
public MqService(ILogger<MqService> logger)
{
@@ -24,144 +25,148 @@ namespace PARR.BLL.Services.Implementations
public MqSendResult Send(IMqSettings mqSettings, string[] msgList)
{
var factory = new ConnectionFactory
{
HostName = mqSettings.HostName,
UserName = mqSettings.User,
Password = mqSettings.Password
};
return new MqSendResult { IsSuccess = false, NotSendMessages = new string[0] };
// индекс текущей отправки в очередь из массива msgList
// нужен для формирования списка неотправленных сообщений
var sendIdx = 0;
//var factory = new ConnectionFactory
//{
// HostName = mqSettings.HostName,
// UserName = mqSettings.User,
// Password = mqSettings.Password
//};
try
{
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
//https://www.rabbitmq.com/lazy-queues.html
//Рекомендовано при работе порциями использовать ленивые очереди. сообщения не используют память
//Формируем соответствующий аргумент
var args = new Dictionary<string, object> { { "x-queue-mode", "lazy" } };
//// индекс текущей отправки в очередь из массива msgList
//// нужен для формирования списка неотправленных сообщений
//var sendIdx = 0;
//Объявляем очередь с которой будем работать.
//Если такой очереди ещё нет, то создатся.
//Если нет, нужно параметры типа durable должны совпадать иначе будет ошибка.
//В целом эти параметры можно посмотреть в админке RabbitMQ
//try
//{
// using (var connection = factory.CreateConnection())
// using (var channel = connection.CreateModel())
// {
// //https://www.rabbitmq.com/lazy-queues.html
// //Рекомендовано при работе порциями использовать ленивые очереди. сообщения не используют память
// //Формируем соответствующий аргумент
// var args = new Dictionary<string, object> { { "x-queue-mode", "lazy" } };
channel.QueueDeclare(
queue: mqSettings.QueueName,
durable: true,
exclusive: false,
autoDelete: false,
arguments: args
);
// //Объявляем очередь с которой будем работать.
// //Если такой очереди ещё нет, то создатся.
// //Если нет, нужно параметры типа durable должны совпадать иначе будет ошибка.
// //В целом эти параметры можно посмотреть в админке RabbitMQ
var props = channel.CreateBasicProperties();
//храним на диске
props.DeliveryMode = 2;
//время жизни, мс
//props.Expiration = "60000";
// channel.QueueDeclare(
// queue: mqSettings.QueueName,
// durable: true,
// exclusive: false,
// autoDelete: false,
// arguments: args
// );
foreach (var msg in msgList)
{
var body = Encoding.UTF8.GetBytes(msg);
channel.BasicPublish(exchange: "", routingKey: mqSettings.QueueName, basicProperties: props, body: body);
// var props = channel.CreateBasicProperties();
// //храним на диске
// props.DeliveryMode = 2;
// //время жизни, мс
// //props.Expiration = "60000";
sendIdx++;
logger.LogDebug($"Отправлено сообщение в очередь: {mqSettings.HostName} {mqSettings.QueueName}, {msg}");
}
}
// foreach (var msg in msgList)
// {
// var body = Encoding.UTF8.GetBytes(msg);
// channel.BasicPublish(exchange: "", routingKey: mqSettings.QueueName, basicProperties: props, body: body);
return new MqSendResult { IsSuccess = true };
}
catch (Exception ex)
{
var notSendMsg = new List<string>();
// sendIdx++;
// logger.LogDebug($"Отправлено сообщение в очередь: {mqSettings.HostName} {mqSettings.QueueName}, {msg}");
// }
// }
// формируем список неотправленных элементов
for (int i = sendIdx; i < msgList.Length; i++)
notSendMsg.Add(msgList[i]);
// return new MqSendResult { IsSuccess = true };
//}
//catch (Exception ex)
//{
// var notSendMsg = new List<string>();
logger.LogError(ex, $"Ошибка при отправке сообщения в очередь {mqSettings.HostName} {mqSettings.QueueName}, {string.Join(',', notSendMsg)}");
// // формируем список неотправленных элементов
// for (int i = sendIdx; i < msgList.Length; i++)
// notSendMsg.Add(msgList[i]);
return new MqSendResult { IsSuccess = false, NotSendMessages = notSendMsg.ToArray() };
}
// logger.LogError(ex, $"Ошибка при отправке сообщения в очередь {mqSettings.HostName} {mqSettings.QueueName}, {string.Join(',', notSendMsg)}");
// return new MqSendResult { IsSuccess = false, NotSendMessages = notSendMsg.ToArray() };
//}
}
public bool InitConsumer(IMqSettings mqSettings, MqMessageHandlerDelegate messageHandler)
{
logger.LogInformation($"Устанавливаю соединение с RabbitMQ: {mqSettings.HostName}, {mqSettings.QueueName}");
var facory = new ConnectionFactory
{
HostName = mqSettings.HostName,
UserName = mqSettings.User,
Password = mqSettings.Password,
AutomaticRecoveryEnabled = true,
DispatchConsumersAsync = true
};
try
{
//using var connection = facory.CreateConnection();
//using var channel = connection.CreateModel();
connection = facory.CreateConnection();
channel = connection.CreateModel();
var args = new Dictionary<string, object> { { "x-queue-mode", "lazy" } };
channel.QueueDeclare(
queue: mqSettings.QueueName,
durable: true,
exclusive: false,
autoDelete: false,
arguments: args
);
logger.LogInformation($"Соединение с RabbitMQ установлено: {mqSettings.HostName}, {mqSettings.QueueName}");
channel.CallbackException += (ch, ea) =>
{
var _channel = (IModel?)ch;
// может тут если канал упал переоткрывать его
logger.LogError(ea.Exception, $"Ошибка при обработке очереди MqService сообщений из очереди. Канал открыт: {_channel?.IsOpen}");
};
var consumer = new AsyncEventingBasicConsumer(channel);
consumer.Received += async (ch, ea) =>
{
var content = Encoding.UTF8.GetString(ea.Body.ToArray());
logger.LogDebug($"Получено сообщение: {content}");
await messageHandler.Invoke(content);
channel.BasicAck(ea.DeliveryTag, false);
await Task.Yield();
};
string consumerTag = channel.BasicConsume(mqSettings.QueueName, false, consumer);
return true;
}
catch (Exception ex)
{
logger.LogError(ex, $"Ошибка при получении сообщений из очереди: {mqSettings.HostName}, {mqSettings.QueueName}");
return false;
}
//var facory = new ConnectionFactory
//{
// HostName = mqSettings.HostName,
// UserName = mqSettings.User,
// Password = mqSettings.Password,
// AutomaticRecoveryEnabled = true,
// DispatchConsumersAsync = true
//};
//try
//{
// //using var connection = facory.CreateConnection();
// //using var channel = connection.CreateModel();
// connection = facory.CreateConnection();
// channel = connection.CreateModel();
// var args = new Dictionary<string, object> { { "x-queue-mode", "lazy" } };
// channel.QueueDeclare(
// queue: mqSettings.QueueName,
// durable: true,
// exclusive: false,
// autoDelete: false,
// arguments: args
// );
// logger.LogInformation($"Соединение с RabbitMQ установлено: {mqSettings.HostName}, {mqSettings.QueueName}");
// channel.CallbackException += (ch, ea) =>
// {
// var _channel = (IModel?)ch;
// // может тут если канал упал переоткрывать его
// logger.LogError(ea.Exception, $"Ошибка при обработке очереди MqService сообщений из очереди. Канал открыт: {_channel?.IsOpen}");
// };
// var consumer = new AsyncEventingBasicConsumer(channel);
// consumer.Received += async (ch, ea) =>
// {
// var content = Encoding.UTF8.GetString(ea.Body.ToArray());
// logger.LogDebug($"Получено сообщение: {content}");
// await messageHandler.Invoke(content);
// channel.BasicAck(ea.DeliveryTag, false);
// await Task.Yield();
// };
// string consumerTag = channel.BasicConsume(mqSettings.QueueName, false, consumer);
// return true;
//}
//catch (Exception ex)
//{
// logger.LogError(ex, $"Ошибка при получении сообщений из очереди: {mqSettings.HostName}, {mqSettings.QueueName}");
// return false;
//}
}
public void Dispose()
{
channel?.Close();
connection?.Close();
//channel?.Close();
//connection?.Close();
channel?.Dispose();
connection?.Dispose();
//channel?.Dispose();
//connection?.Dispose();
}
}
}

View File

@@ -0,0 +1,203 @@
using Microsoft.Extensions.Logging;
using PARR.BLL.Contracts.Interfaces;
using PARR.BLL.Domain.Mq;
using PARR.BLL.Services.Interfaces;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
namespace PARR.BLL.Services.Implementations
{
internal class MqServiceV2 : IMqService
{
private readonly ILogger<MqServiceV2> logger;
private IConnection? consumerConnection;
private IChannel? consumerChannel;
// реализация для RabbitMQ.Client 7.1.2
public MqServiceV2(ILogger<MqServiceV2> logger)
{
this.logger = logger;
}
public async Task<bool> InitConsumerAsync(IMqSettings mqSettings, MqMessageHandlerDelegate messageHandler)
{
logger.LogInformation($"Устанавливаю соединение с RabbitMQ: {mqSettings.HostName}, {mqSettings.QueueName}");
var factory = new ConnectionFactory
{
HostName = mqSettings.HostName,
UserName = mqSettings.User,
Password = mqSettings.Password,
AutomaticRecoveryEnabled = true
};
try
{
consumerConnection = await factory.CreateConnectionAsync();
consumerChannel = await consumerConnection.CreateChannelAsync();
// кол-во сообщений которые можно обрабатывать за раз
if (mqSettings.PrefetchCount.HasValue)
{
await consumerChannel.BasicQosAsync(0, mqSettings.PrefetchCount.Value, false);
}
// создаем очередь, вдруг ее еще нет
await QueueDeclareAsync(consumerChannel, mqSettings);
//await consumerChannel.QueueBindAsync(mqSettings.QueueName, "default", "routingKey");
consumerChannel.CallbackExceptionAsync += async (ch, ea) =>
{
var _channel = (IChannel?)ch;
// может тут если канал упал переоткрывать его
logger.LogError(ea.Exception, $"Ошибка при обработке очереди MqService сообщений из очереди. Канал открыт?: {_channel?.IsOpen}");
//if (consumerChannel.IsClosed)
//{
// //todo: этот момент проверить, успешно ли он переоткроет канал и очередь будет дальше обрабатываться
// await consumerChannel.CloseAsync();
// consumerChannel = await consumerConnection.CreateChannelAsync();
// logger.LogInformation(ea.Exception, $"Переоткрыл канал RabbitMq.");
//}
};
var consumer = new AsyncEventingBasicConsumer(consumerChannel);
//consumer.HandleChannelShutdownAsync = async (c, ea) =>{ };
consumer.ReceivedAsync += async (ch, ea) =>
{
var content = Encoding.UTF8.GetString(ea.Body.ToArray());
logger.LogDebug($"Получено сообщение: {content}");
await messageHandler.Invoke(content);
await consumerChannel.BasicAckAsync(ea.DeliveryTag, false);
};
var consumerTag = await consumerChannel.BasicConsumeAsync(mqSettings.QueueName, false, consumer);
return true;
}
catch (Exception ex)
{
logger.LogError(ex, $"Ошибка при получении сообщений из очереди: {mqSettings.HostName}, {mqSettings.QueueName}");
return false;
}
}
public async Task<MqSendResult> SendAsync(IMqSettings mqSettings, string[] msgList)
{
var factory = new ConnectionFactory
{
HostName = mqSettings.HostName,
UserName = mqSettings.User,
Password = mqSettings.Password,
AutomaticRecoveryEnabled = true
};
// индекс текущей отправки в очередь из массива msgList
// нужен для формирования списка неотправленных сообщений
var sendIdx = 0;
try
{
using (var connection = await factory.CreateConnectionAsync())
using (var channel = await connection.CreateChannelAsync())
{
// создаем очередь, вдруг ее еще нет
await QueueDeclareAsync(channel, mqSettings);
var props = new BasicProperties();
//храним на диске
props.DeliveryMode = DeliveryModes.Persistent;
//время жизни, мс
props.Expiration = "60000";
props.ContentType = "text/plain";//"application/json";
foreach (var msg in msgList)
{
var body = Encoding.UTF8.GetBytes(msg);
await channel.BasicPublishAsync(
exchange: "",
routingKey: mqSettings.QueueName,
//TODO: проверить mandatory: true, может указать его в false
mandatory: true,
basicProperties: props,
body: body
);
sendIdx++;
logger.LogDebug($"Отправлено сообщение в очередь: {mqSettings.HostName} {mqSettings.QueueName}, {msg}");
}
}
return new MqSendResult { IsSuccess = true };
}
catch (Exception ex)
{
var notSendMsg = new List<string>();
// формируем список неотправленных элементов
for (int i = sendIdx; i < msgList.Length; i++)
notSendMsg.Add(msgList[i]);
logger.LogError(ex, $"Ошибка при отправке сообщения в очередь {mqSettings.HostName} {mqSettings.QueueName}, {string.Join(',', notSendMsg)}");
return new MqSendResult { IsSuccess = false, NotSendMessages = notSendMsg.ToArray() };
}
}
private async Task QueueDeclareAsync(IChannel channel, IMqSettings mqSettings)
{
//https://www.rabbitmq.com/lazy-queues.html
// lazy - ленивой очереди больше нет
var args = new Dictionary<string, object?> { { "x-queue-mode", "lazy" } };
//Объявляем очередь с которой будем работать.
//Если такой очереди ещё нет, то создатся.
//Если нет, нужно параметры типа durable должны совпадать иначе будет ошибка.
//В целом эти параметры можно посмотреть в админке RabbitMQ
await channel.QueueDeclareAsync(
queue: mqSettings.QueueName,
durable: true,
exclusive: false,
autoDelete: false,
arguments: args
);
}
public async ValueTask DisposeAsync()
{
if (consumerChannel != null)
{
if (consumerChannel.IsOpen)
{
await consumerChannel.CloseAsync();
}
await consumerChannel.DisposeAsync();
}
if (consumerConnection != null)
{
if (consumerConnection.IsOpen)
{
await consumerConnection.CloseAsync();
}
await consumerConnection.DisposeAsync();
}
}
}
}

View File

@@ -5,9 +5,9 @@ namespace PARR.BLL.Services.Interfaces
{
public delegate Task MqMessageHandlerDelegate(string msg);
public interface IMqService : IDisposable
public interface IMqService : IAsyncDisposable // IDisposable
{
bool InitConsumer(IMqSettings mqSettings, MqMessageHandlerDelegate messageHandler);
MqSendResult Send(IMqSettings mqSettings, string[] msgList);
Task<bool> InitConsumerAsync(IMqSettings mqSettings, MqMessageHandlerDelegate messageHandler);
Task<MqSendResult> SendAsync(IMqSettings mqSettings, string[] msgList);
}
}

View File

@@ -8,6 +8,7 @@ using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
using PARR.EsppOrderManager.Services;
using PARR.EsppOrderManager.Settings;
using System.Threading.Tasks;
namespace PARR.EsppOrderManager
{
@@ -40,11 +41,11 @@ namespace PARR.EsppOrderManager
this.resultTemplateSettings = resultTemplateSettings;
}
public void Start()
public async Task StartAsync()
{
// логика работы описана в документации
var isConnected = mqService.InitConsumer(mqSettings, ManageOrderAsync);
var isConnected = await mqService.InitConsumerAsync(mqSettings, ManageOrderAsync);
if (!isConnected)
throw new Exception("Ошибка при подключении к RabbitMq");
@@ -53,9 +54,9 @@ namespace PARR.EsppOrderManager
//await ManageOrderAsync("{\"OrderId\":\"49191af5-c313-4388-9720-a61fd13f15a8\"}");
}
public void Stop()
public async Task StopAsync()
{
mqService.Dispose();
await mqService.DisposeAsync();
}

View File

@@ -2,7 +2,7 @@
{
public interface IEsppOrderManager
{
void Start();
void Stop();
Task StartAsync();
Task StopAsync();
}
}

View File

@@ -8,5 +8,6 @@ namespace PARR.EsppOrderManager.Settings
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;
}
}

View File

@@ -15,12 +15,12 @@ namespace PARR.EsppOrderManagerWorker
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
esppOrderManager.Start();
await esppOrderManager.StartAsync();
}
public override Task StopAsync(CancellationToken cancellationToken)
{
esppOrderManager.Stop();
esppOrderManager.StopAsync().Wait();
return base.StopAsync(cancellationToken);
}

View File

@@ -2,7 +2,7 @@
{
public interface IScheduleSyncher
{
void Start();
void Stop();
Task StartAsync();
Task StopAsync();
}
}

View File

@@ -20,7 +20,7 @@ namespace PARR.EsppScheduleSync
private readonly ISyncService<EsppObjectSchedule> syncService;
private readonly SettingsFromDb settingsFromDb;
private readonly IServiceProvider serviceProvider;
private readonly INextRunModifierService nextRunModifierService;
//private readonly INextRunModifierService nextRunModifierService;
public ScheduleSyncher(
ILogger<ScheduleSyncher> logger,
@@ -28,8 +28,8 @@ namespace PARR.EsppScheduleSync
IMqService mqService,
ISyncService<EsppObjectSchedule> syncService,
SettingsFromDb settingsFromDb,
IServiceProvider serviceProvider,
INextRunModifierService nextRunModifierService
IServiceProvider serviceProvider
//INextRunModifierService nextRunModifierService
)
{
this.logger = logger;
@@ -38,7 +38,7 @@ namespace PARR.EsppScheduleSync
this.syncService = syncService;
this.settingsFromDb = settingsFromDb;
this.serviceProvider = serviceProvider;
this.nextRunModifierService = nextRunModifierService;
//this.nextRunModifierService = nextRunModifierService;
if (globalSettings.MqSettings == null)
{
logger.LogError("Нет секции настроек хранилища. MqSettings, EsppTemplates");
@@ -47,9 +47,9 @@ namespace PARR.EsppScheduleSync
}
public void Start()
public async Task StartAsync()
{
var isConnected = mqService.InitConsumer(globalSettings!.MqSettings!, SyncScheduleAsync);
var isConnected = await mqService.InitConsumerAsync(globalSettings!.MqSettings!, SyncScheduleAsync);
if (!isConnected)
throw new Exception("Ошибка при подключении к RabbitMq");
@@ -58,9 +58,9 @@ namespace PARR.EsppScheduleSync
}
public void Stop()
public async Task StopAsync()
{
mqService.Dispose();
await mqService.DisposeAsync();
logger.LogInformation($"=== === === Соединение с очередью {globalSettings.MqSettings!.QueueName} закрыто === === ===");
}
@@ -80,6 +80,19 @@ namespace PARR.EsppScheduleSync
/// <exception cref="NotImplementedException"></exception>
private EsppObjectSchedule ConvertDbObjToEsppObj(Template template)
{
//дефолтное значение, изменится в сервисе nextRunModifierService
var nextRunByAccountRobotTimeZone = DateTimeOffset.MinValue;
using (var scope = serviceProvider.CreateScope())
{
var nextRunModifierService = scope.ServiceProvider.GetService<INextRunModifierService>();
if (nextRunModifierService == null)
throw new Exception($"Не найден сервис: {nameof(INextRunModifierService)}");
nextRunByAccountRobotTimeZone = nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun);
}
var esppObjectFromDb = new EsppObjectSchedule
{
TemplateName = template.Name,
@@ -92,8 +105,10 @@ namespace PARR.EsppScheduleSync
//Мы решили, что для всех расписаний "Нет исключений", если что-то поменяется, тут нужно переделать
TypeV60calendar = settingsFromDb.ScheduleExclude == "Нет исключений" ? "NONE" : "",
//Scheduled = EsppScheduleHelpers.GetNextRun(template.NextRun),
Scheduled = EsppScheduleHelpers.GetNextRun(nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun)),
BasisTime = EsppScheduleHelpers.GetGenerationTime(nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun)),
//Scheduled = EsppScheduleHelpers.GetNextRun(nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun)),
//BasisTime = EsppScheduleHelpers.GetGenerationTime(nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun)),
Scheduled = EsppScheduleHelpers.GetNextRun(nextRunByAccountRobotTimeZone),
BasisTime = EsppScheduleHelpers.GetGenerationTime(nextRunByAccountRobotTimeZone),
Timezone = settingsFromDb.ScheduleTimezone,
//Мы решили, что для всех расписаний "Отсутствует дата завершения", если что-то поменяется, тут нужно переделать
TerminationType = settingsFromDb.ScheduleRepeatRange == "Отсутствует дата завершения" ? "forever" : "",

View File

@@ -14,5 +14,6 @@ namespace PARR.EsppScheduleSync.Settings
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;
}
}

View File

@@ -1,4 +1,3 @@
using PARR.DAL.TransformServices;
using PARR.EsppScheduleSync;
namespace PARR.EsppScheduleSyncWorker
@@ -16,12 +15,12 @@ namespace PARR.EsppScheduleSyncWorker
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
scheduleSyncher.Start();
await scheduleSyncher.StartAsync();
}
public override Task StopAsync(CancellationToken cancellationToken)
{
scheduleSyncher.Stop();
scheduleSyncher.StopAsync().Wait();
return base.StopAsync(cancellationToken);
}

View File

@@ -32,7 +32,8 @@
"HostName": "parr-rabbitmq",
"QueueName": "parr-espp-schedulers",
"User": "espp_schedulers_reader",
"Password": "KjdhGLJDshgd&^%84S2"
"Password": "KjdhGLJDshgd&^%84S2",
"PrefetchCount": 100
},
"ParsingSeparator": "<|>"
}

View File

@@ -12,21 +12,25 @@ namespace PARR.EsppSync
internal class SyncService<EsppObject> : ISyncService<EsppObject> where EsppObject : class, IEsppObject
{
private readonly ILogger<SyncService<EsppObject>> logger;
private readonly ITemplateService templateService;
private readonly IRobotConfigurationService robotConfigurationService;
private readonly IShortcodesService shortcodesService;
private readonly IServiceProvider serviceProvider;
//private readonly ITemplateService templateService;
//private readonly IRobotConfigurationService robotConfigurationService;
//private readonly IShortcodesService shortcodesService;
public SyncService(
ILogger<SyncService<EsppObject>> logger,
ITemplateService templateService,
IRobotConfigurationService robotConfigurationService,
IShortcodesService shortcodesService
IServiceProvider serviceProvider
//ITemplateService templateService,
//IRobotConfigurationService robotConfigurationService,
//IShortcodesService shortcodesService
)
{
this.logger = logger;
this.templateService = templateService;
this.robotConfigurationService = robotConfigurationService;
this.shortcodesService = shortcodesService;
this.serviceProvider = serviceProvider;
//this.templateService = templateService;
//this.robotConfigurationService = robotConfigurationService;
//this.shortcodesService = shortcodesService;
}
@@ -52,6 +56,13 @@ namespace PARR.EsppSync
return;
}
using (var scope = serviceProvider.CreateScope())
{
var templateService = GetServiceInScope<ITemplateService>(scope);
var robotConfigurationService = GetServiceInScope<IRobotConfigurationService>(scope);
var shortcodesService = GetServiceInScope<IShortcodesService>(scope);
try
{
var template = await templateService.GetTemplateByNameAsync(esppObject.TemplateName);
@@ -154,6 +165,7 @@ namespace PARR.EsppSync
logger.LogError(ex, $"Ошибка синхронизации объекта АСУ ЕСПП {esppObject.TemplateName}");
}
}
}
private void SetUpdateStatus(ref Template template, IRobotConfigurationService robotConfigurationService, RobotsEnum robot)

View File

@@ -2,7 +2,7 @@
{
public interface ITemplateSyncer
{
void Start();
void Stop();
Task StartAsync();
Task StopAsync();
}
}

View File

@@ -17,6 +17,7 @@ namespace PARR.EsppTemplateSync.Settings
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;
}
internal class StorageSettings

View File

@@ -39,7 +39,7 @@ namespace PARR.EsppTemplateSync
filterExtensions = string.Join(",", storageSettings.EsppTemplates!.AllowedExtensions).Replace(".", "*.");
}
public void Start()
public void StartAsync()
{
//смотрим, доступна ли папка
if (!Directory.Exists(dirPath))
@@ -80,7 +80,7 @@ namespace PARR.EsppTemplateSync
}
public void Stop()
public void StopAsync()
{
//watcher?.Dispose();
logger.LogInformation($"=== === === FileWatcher остановлен === === ===");
@@ -132,5 +132,14 @@ namespace PARR.EsppTemplateSync
//}
}
Task ITemplateSyncer.StartAsync()
{
throw new NotImplementedException();
}
Task ITemplateSyncer.StopAsync()
{
throw new NotImplementedException();
}
}
}

View File

@@ -15,21 +15,25 @@ namespace PARR.EsppTemplateSync
private readonly GlobalSettings globalSettings;
private readonly IMqService mqService;
private readonly SettingsFromDb settingsFromDb;
private readonly IServiceProvider serviceProvider;
private readonly ISyncService<EsppObjectTemplate> syncService;
//private readonly IServiceProvider serviceProvider;
public TemplateMQSyncer(
ILogger<TemplateMQSyncer> logger,
GlobalSettings globalSettings,
IMqService mqService,
SettingsFromDb settingsFromDb,
IServiceProvider serviceProvider
ISyncService<EsppObjectTemplate> syncService
//IServiceProvider serviceProvider
)
{
this.logger = logger;
this.globalSettings = globalSettings;
this.mqService = mqService;
this.settingsFromDb = settingsFromDb;
this.serviceProvider = serviceProvider;
this.syncService = syncService;
//this.serviceProvider = serviceProvider;
if (globalSettings.MqSettings == null)
{
logger.LogError("Нет секции настроек хранилища. MqSettings, EsppTemplates");
@@ -37,10 +41,10 @@ namespace PARR.EsppTemplateSync
}
}
public void Start()
public async Task StartAsync()
{
var isConnected = mqService.InitConsumer(globalSettings!.MqSettings!, SyncTemplateAsync);
var isConnected = await mqService.InitConsumerAsync(globalSettings!.MqSettings!, SyncTemplateAsync);
if (!isConnected)
throw new Exception("Ошибка при подключении к RabbitMq");
@@ -48,9 +52,9 @@ namespace PARR.EsppTemplateSync
logger.LogInformation($"Запущена проверка очереди {globalSettings.MqSettings!.QueueName}.");
}
public void Stop()
public async Task StopAsync()
{
mqService.Dispose();
await mqService.DisposeAsync();
logger.LogInformation($"=== === === Соединение с очередью {globalSettings.MqSettings!.QueueName} закрыто === === ===");
}
@@ -58,15 +62,15 @@ namespace PARR.EsppTemplateSync
private async Task SyncTemplateAsync(string str)
{
using (var scope = serviceProvider.CreateScope())
{
var syncService = scope.ServiceProvider.GetService<ISyncService<EsppObjectTemplate>>();
//using (var scope = serviceProvider.CreateScope())
//{
// var syncService = scope.ServiceProvider.GetService<ISyncService<EsppObjectTemplate>>();
if (syncService == null)
throw new Exception($"Не смог получить серивс {nameof(ITemplateSyncer)}");
// if (syncService == null)
// throw new Exception($"Не смог получить серивс {nameof(ITemplateSyncer)}");
await syncService.SyncEsppObjectAsync(str, ParseStrToEsppObject, ConvertDbObjToEsppObj);
}
//}
}

View File

@@ -20,12 +20,12 @@ namespace PARR.EsppTemplateSyncWorker
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
templateSyncer.Start();
await templateSyncer.StartAsync();
}
public override Task StopAsync(CancellationToken cancellationToken)
{
templateSyncer.Stop();
templateSyncer.StopAsync().Wait();
return base.StopAsync(cancellationToken);
}
}

View File

@@ -39,7 +39,8 @@
"HostName": "parr-rabbitmq",
"QueueName": "parr-espp-templates",
"User": "espp_templates_reader",
"Password": "P@ssReaderPtk202!"
"Password": "P@ssReaderPtk202!",
"PrefetchCount": 100
},
"StorageSettings": {
"CheckIntervalSeconds": 30

View File

@@ -6,6 +6,7 @@ using PARR.BLL.Services.Interfaces;
using PARR.DAL.Models;
using PARR.GeneratorTemplates.Services;
using PARR.GeneratorTemplates.Settings;
using System.Threading.Tasks;
namespace PARR.GeneratorTemplates
{
@@ -35,7 +36,7 @@ namespace PARR.GeneratorTemplates
this.serviceProvider = serviceProvider;
}
public void Start()
public async Task StartAsync()
{
#region test
// string msg = "{\"WorkId\":\"91219bec-e5f7-4a1a-b4c9-c135035d2498\",\"ApplicationId\":\"13044a1f-fa0c-476f-b501-2b8d06bac9f8\",\"Action\":\"create\",\"Ek\":\"ВРТ*ДВС\",\"StatusEk\":0}";
@@ -44,15 +45,15 @@ namespace PARR.GeneratorTemplates
// await GenerateTemplates(msg);
#endregion
var isConnected = mqService.InitConsumer(mqSettings, GenerateTemplates);
var isConnected = await mqService.InitConsumerAsync(mqSettings, GenerateTemplates);
if (!isConnected)
throw new Exception("Ошибка при подключении к RabbitMq");
}
public void Stop()
public async Task StopAsync()
{
mqService.Dispose();
await mqService.DisposeAsync();
}

View File

@@ -2,7 +2,7 @@
{
public interface IGeneratorTemplate
{
void Start();
void Stop();
Task StartAsync();
Task StopAsync();
}
}

View File

@@ -8,5 +8,6 @@ namespace PARR.GeneratorTemplates.Settings
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;
}
}

View File

@@ -15,7 +15,7 @@ namespace PARR.GeneratorTemplatesWorker
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
generatorTemplate.Start();
await generatorTemplate.StartAsync();
//while (!stoppingToken.IsCancellationRequested)
//{
// _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
@@ -25,7 +25,7 @@ namespace PARR.GeneratorTemplatesWorker
public override Task StopAsync(CancellationToken cancellationToken)
{
generatorTemplate.Stop();
generatorTemplate.StopAsync().Wait();
return base.StopAsync(cancellationToken);
}

View File

@@ -87,7 +87,8 @@ namespace PARR.JobAutoControl
{
job.JobEkMasks.ToList().ForEach(ek =>
{
job.JobAutoControlInEkStatuses.ToList().ForEach(ekStatus =>
//todo: проверить, нормально ли отрабатывает async в Foreach
job.JobAutoControlInEkStatuses.ToList().ForEach(async ekStatus =>
{
var request = new GeneratorTemplateMq
{
@@ -103,7 +104,7 @@ namespace PARR.JobAutoControl
var msg = JsonSerializer.Serialize(request);
var result = mqService.Send(mqSettings.Generator, new[] { msg });
var result =await mqService.SendAsync(mqSettings.Generator, new[] { msg });
if (result.IsSuccess)
logger.LogInformation($"Отправлен запрос на генерацию: {msg}");
@@ -135,7 +136,8 @@ namespace PARR.JobAutoControl
if (!jobsToDeactivate.Any())
return;
jobsToDeactivate.ForEach(applicationInWorkId =>
//todo: проверить, нормально ли отрабатывает async в foreach
jobsToDeactivate.ForEach(async applicationInWorkId =>
{
var request = new TemplateActivatorMq
{
@@ -146,7 +148,7 @@ namespace PARR.JobAutoControl
var msg = JsonSerializer.Serialize(request);
var result = mqService.Send(mqSettings.Activator, new[] { msg });
var result = await mqService.SendAsync(mqSettings.Activator, new[] { msg });
if (result.IsSuccess)
logger.LogInformation($"Отправлен запрос на деактивацию: {msg}");
@@ -174,7 +176,8 @@ namespace PARR.JobAutoControl
if (!jobsToActivate.Any())
return;
jobsToActivate.ForEach(applicationInWorkId =>
//todo: проверить, нормально ли отрабатывает async в foreach
jobsToActivate.ForEach(async applicationInWorkId =>
{
var request = new TemplateActivatorMq
{
@@ -185,7 +188,7 @@ namespace PARR.JobAutoControl
var msg = JsonSerializer.Serialize(request);
var result = mqService.Send(mqSettings.Activator, new[] { msg });
var result = await mqService.SendAsync(mqSettings.Activator, new[] { msg });
if (result.IsSuccess)
logger.LogInformation($"Отправлен запрос на активацию: {msg}");

View File

@@ -14,6 +14,7 @@ namespace PARR.JobAutoControl.Settings
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;
}
internal class Activator : IMqSettings
@@ -22,6 +23,7 @@ namespace PARR.JobAutoControl.Settings
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;
}

View File

@@ -66,7 +66,7 @@ namespace PARR.Master.Services
if (objs.Any())
{
var sendResult = mqService.Send(mqSettings, objs.ToArray());
var sendResult = await mqService.SendAsync(mqSettings, objs.ToArray());
if (sendResult.IsSuccess)
{
logger.LogInformation($"Наряды переданы в RabbitMQ: {objs.Count()}");

View File

@@ -8,5 +8,6 @@ namespace PARR.Master.Settings
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;
}
}

View File

@@ -6,44 +6,45 @@ namespace PARR.MockData
{
internal class EsppDataImporter
{
public void Import() {
var factory = new ConnectionFactory() { HostName = "10.99.253.216" };
factory.UserName = "espp_templates_robot";
factory.Password = "P@ssRwEsppTempl202";
string[] rows = EsppExport.data.Replace("\r", "").Split('\n');
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
public void Import()
{
//https://www.rabbitmq.com/lazy-queues.html
//Рекомендовано при работе порциями использовать ленивые очереди. сообщения не используют память
//Формируем соответствующий аргумент
Dictionary<String, Object> argums = new Dictionary<String, Object>();
argums.Add("x-queue-mode", "lazy");
//var factory = new ConnectionFactory() { HostName = "10.99.253.216" };
//factory.UserName = "espp_templates_robot";
//factory.Password = "P@ssRwEsppTempl202";
//Объявляем очередь с которой будем работать. Если такой очереди ещё нет, то создатся. Если нет, нужно параметры типа durable должны совпадать иначе будет ошибка. В целом эти параметры можно посмотреть в админке RabbitMQ
channel.QueueDeclare(queue: "parr-espp-templates",
durable: true,//If you want to make sure your messages are persisted, you need to create a durable queue. To do this, simply set the durable flag to true when creating the queue.
exclusive: false,
autoDelete: false,
arguments: argums);
//перебираем строки и отправляем строки сообщениями
for (int i = 0; i < rows.Count(); i++)
{
var body = Encoding.UTF8.GetBytes(rows[i]);
IBasicProperties props = channel.CreateBasicProperties();
//If you dont mark your messages as persistent, then RabbitMQ will store them in memory. This is fine if youre just playing around or building a prototype. But if youre building a production system, then you need to make sure that your messages are persisted to disk so that theyre not lost if the server crashes.
//Говорим менеджеру RabbitMq при получении хранить сообщения на диске
props.DeliveryMode = 2;
//время жизни в мс. на этапе отладки сделаем коротким чтобы не устраивать помойку
props.Expiration = "60000";
//string[] rows = EsppExport.data.Replace("\r", "").Split('\n');
//using (var connection = factory.CreateConnection())
//using (var channel = connection.CreateModel())
//{
// //https://www.rabbitmq.com/lazy-queues.html
// //Рекомендовано при работе порциями использовать ленивые очереди. сообщения не используют память
// //Формируем соответствующий аргумент
// Dictionary<String, Object> argums = new Dictionary<String, Object>();
// argums.Add("x-queue-mode", "lazy");
channel.BasicPublish(exchange: "",
routingKey: "parr-espp-templates",//совпадает с именем очереди иначе не принимает
basicProperties: props,
body: body);
}
}
// //Объявляем очередь с которой будем работать. Если такой очереди ещё нет, то создатся. Если нет, нужно параметры типа durable должны совпадать иначе будет ошибка. В целом эти параметры можно посмотреть в админке RabbitMQ
// channel.QueueDeclare(queue: "parr-espp-templates",
// durable: true,//If you want to make sure your messages are persisted, you need to create a durable queue. To do this, simply set the durable flag to true when creating the queue.
// exclusive: false,
// autoDelete: false,
// arguments: argums);
// //перебираем строки и отправляем строки сообщениями
// for (int i = 0; i < rows.Count(); i++)
// {
// var body = Encoding.UTF8.GetBytes(rows[i]);
// IBasicProperties props = channel.CreateBasicProperties();
// //If you dont mark your messages as persistent, then RabbitMQ will store them in memory. This is fine if youre just playing around or building a prototype. But if youre building a production system, then you need to make sure that your messages are persisted to disk so that theyre not lost if the server crashes.
// //Говорим менеджеру RabbitMq при получении хранить сообщения на диске
// props.DeliveryMode = 2;
// //время жизни в мс. на этапе отладки сделаем коротким чтобы не устраивать помойку
// props.Expiration = "60000";
// channel.BasicPublish(exchange: "",
// routingKey: "parr-espp-templates",//совпадает с именем очереди иначе не принимает
// basicProperties: props,
// body: body);
// }
//}
}
}

View File

@@ -10,7 +10,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="RabbitMQ.Client" Version="6.5.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="7.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />

View File

@@ -2,6 +2,6 @@
public interface IMqTemplateActivator
{
void Start();
void Stop();
Task StartAsync();
Task StopAsync();
}

View File

@@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging;
using PARR.BLL.Domain.Mq;
using PARR.BLL.Services.Interfaces;
using PARR.Constants;
using System.Threading.Tasks;
namespace PARR.TemplateActivator;
@@ -31,9 +32,9 @@ internal class MqTemplateActivator : IMqTemplateActivator
this.validatorService = validatorService;
this.serviceProvider = serviceProvider;
}
public void Start()
public async Task StartAsync()
{
var isConnected = mqService.InitConsumer(mqSettings, UpdateTemplateStatusAsync);
var isConnected = await mqService.InitConsumerAsync(mqSettings, UpdateTemplateStatusAsync);
if (!isConnected)
throw new Exception("Ошибка при подключении к RabbitMq");
@@ -64,8 +65,8 @@ internal class MqTemplateActivator : IMqTemplateActivator
}
}
public void Stop()
public async Task StopAsync()
{
mqService.Dispose();
await mqService.DisposeAsync();
}
}

View File

@@ -8,5 +8,6 @@ internal class MqSettings : IMqSettings
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;
}

View File

@@ -15,12 +15,12 @@ namespace PARR.TemplateActivatorWorker
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
mqTemplateActivator.Start();
await mqTemplateActivator.StartAsync();
}
public override Task StopAsync(CancellationToken cancellationToken)
{
mqTemplateActivator.Stop();
mqTemplateActivator.StopAsync().Wait();
return base.StopAsync(cancellationToken);
}

View File

@@ -2,7 +2,7 @@
{
public interface IMqTemplateDistributor
{
void Start();
void Stop();
Task StartAsync();
Task StopAsync();
}
}

View File

@@ -4,6 +4,7 @@ using PARR.BLL.Domain.Mq;
using PARR.BLL.Services.Interfaces;
using PARR.TemplateDistributor.Services;
using PARR.TemplateDistributor.Settings;
using System.Threading.Tasks;
namespace PARR.TemplateDistributor
{
@@ -31,18 +32,18 @@ namespace PARR.TemplateDistributor
this.validatorService = validatorService;
this.serviceProvider = serviceProvider;
}
public void Start()
public async Task StartAsync()
{
var isConnected = mqService.InitConsumer(mqSettings, UpdateScheduleAsync);
var isConnected = await mqService.InitConsumerAsync(mqSettings, UpdateScheduleAsync);
if (!isConnected)
throw new Exception("Ошибка при подключении к RabbitMq");
}
public void Stop()
public async Task StopAsync()
{
mqService.Dispose();
await mqService.DisposeAsync();
}
private async Task UpdateScheduleAsync(string msg)

View File

@@ -8,5 +8,6 @@ namespace PARR.TemplateDistributor.Settings
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;
}
}

View File

@@ -15,12 +15,12 @@ namespace PARR.TemplateDistributorWorker
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
mqTemplateDistributor.Start();
await mqTemplateDistributor.StartAsync();
}
public override Task StopAsync(CancellationToken cancellationToken)
{
mqTemplateDistributor.Stop();
mqTemplateDistributor.StopAsync().Wait();
return base.StopAsync(cancellationToken);
}

View File

@@ -35,19 +35,16 @@ namespace PARR.TemplateGeneratorWorker
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var isConnected = mqService.InitConsumer(mqSettings, GenerateTemplateAsync);
var isConnected = await mqService.InitConsumerAsync(mqSettings, GenerateTemplateAsync);
if (!isConnected)
throw new Exception("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> RabbitMq");
}
}
public override Task StopAsync(CancellationToken cancellationToken)
{
mqService.Dispose();
mqService.DisposeAsync().AsTask().Wait();
return base.StopAsync(cancellationToken);
}