Merge branch 'update-rqbbitmq' into dev
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
{
|
||||
public interface IAihitMainSyncer
|
||||
{
|
||||
void Start();
|
||||
Task StartAsync();
|
||||
|
||||
|
||||
void Stop();
|
||||
Task StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
public interface IAihitSyncer
|
||||
{
|
||||
void Start();
|
||||
void Stop();
|
||||
Task StartAsync();
|
||||
Task StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"HostName": "10.99.253.216",
|
||||
"QueueName": "parr-aihit-data",
|
||||
"User": "aihit_syncer",
|
||||
"Password": "afsdgDGjhfiU76496as42!@"
|
||||
"Password": "afsdgDGjhfiU76496as42!@",
|
||||
"PrefetchCount": 100
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>(), "Отправлен запрос на перераспределение регламентных работ."));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = $"Ошибка при отправке данных." } }));
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
203
PARR.BLL/Services/Implementations/MqServiceV2.cs
Normal file
203
PARR.BLL/Services/Implementations/MqServiceV2.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
public interface IEsppOrderManager
|
||||
{
|
||||
void Start();
|
||||
void Stop();
|
||||
Task StartAsync();
|
||||
Task StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
public interface IScheduleSyncher
|
||||
{
|
||||
void Start();
|
||||
void Stop();
|
||||
Task StartAsync();
|
||||
Task StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" : "",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
"HostName": "parr-rabbitmq",
|
||||
"QueueName": "parr-espp-schedulers",
|
||||
"User": "espp_schedulers_reader",
|
||||
"Password": "KjdhGLJDshgd&^%84S2"
|
||||
"Password": "KjdhGLJDshgd&^%84S2",
|
||||
"PrefetchCount": 100
|
||||
},
|
||||
"ParsingSeparator": "<|>"
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
public interface ITemplateSyncer
|
||||
{
|
||||
void Start();
|
||||
void Stop();
|
||||
Task StartAsync();
|
||||
Task StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
public interface IGeneratorTemplate
|
||||
{
|
||||
void Start();
|
||||
void Stop();
|
||||
Task StartAsync();
|
||||
Task StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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}");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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()}");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 don’t mark your messages as persistent, then RabbitMQ will store them in memory. This is fine if you’re just playing around or building a prototype. But if you’re building a production system, then you need to make sure that your messages are persisted to disk so that they’re 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 don’t mark your messages as persistent, then RabbitMQ will store them in memory. This is fine if you’re just playing around or building a prototype. But if you’re building a production system, then you need to make sure that your messages are persisted to disk so that they’re not lost if the server crashes.
|
||||
// //Говорим менеджеру RabbitMq при получении хранить сообщения на диске
|
||||
// props.DeliveryMode = 2;
|
||||
// //время жизни в мс. на этапе отладки сделаем коротким чтобы не устраивать помойку
|
||||
// props.Expiration = "60000";
|
||||
|
||||
// channel.BasicPublish(exchange: "",
|
||||
// routingKey: "parr-espp-templates",//совпадает с именем очереди иначе не принимает
|
||||
// basicProperties: props,
|
||||
// body: body);
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
public interface IMqTemplateActivator
|
||||
{
|
||||
void Start();
|
||||
void Stop();
|
||||
Task StartAsync();
|
||||
Task StopAsync();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
public interface IMqTemplateDistributor
|
||||
{
|
||||
void Start();
|
||||
void Stop();
|
||||
Task StartAsync();
|
||||
Task StopAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user