using System; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using RabbitMQ.Client; using RabbitMQ.Client.Events; using xCommons.Extensions; using xEventService.Configuration; using xEventService.Constants; using xEventService.Extensions; using xEventService.Models; using xExceptions.Constants; namespace xEventService.Providers { /// /// an Abstract Kafka Consumer Service ... /// public abstract class XRabbitMQConsumerServiceBase : XBaseEventConsumerBackgroundService { protected IModel channel; protected IConnection connection; protected AsyncEventingBasicConsumer consumer; protected XRabbitMQConsumerServiceBase( string[] allowedActions, string[] allowedSenders, IServiceProvider serviceProvider, XEventServiceConfiguration configuration, ILogger logger, string topic = XEventServiceConstants.XDefaultTopic ) : base( topic: topic, logger: logger, configuration: configuration, allowedActions: allowedActions, allowedSenders: allowedSenders, serviceProvider: serviceProvider ) { // // Validating Configuration ... if (!configuration.RabbitMQ.IsValid() || configuration.Broker != XEventBroker.XRabbitMQ ) { XException.InvalidConfiguration.Throw(); } // SetupConnection(); DeclareTopology(); consumer = new AsyncEventingBasicConsumer(channel); } /// /// Default Action Execution for Background Services ... /// /// /// protected override async Task ExecuteAsync( CancellationToken cancellationToken = default ) { // // For Fix Blocking Synchronous ... await Task.Yield(); using var cts = new CancellationTokenSource(); // // Subscribe to Topic ... consumer.Received += async (model, ea) => { // try { // var body = ea.Body.ToArray(); var json = Encoding.UTF8.GetString(body); var message = json.FromJSON(); if (!message.IsNullOrDefault()) { // await DoWorkAsync( payload: message, cancellationToken: cancellationToken ); } // if (configuration.RabbitMQ.ManualAck) { // channel.BasicAck( multiple: false, deliveryTag: ea.DeliveryTag ); } } catch { // if (configuration.RabbitMQ.ManualAck) { // channel.BasicNack( requeue: true, multiple: false, deliveryTag: ea.DeliveryTag ); } } }; // consumer.Shutdown += (model, ea) => { return Task.CompletedTask; }; // channel.BasicQos( prefetchSize: 0, global: false, prefetchCount: configuration.RabbitMQ.PrefetchCount ); // channel.BasicConsume( queue: GetQueueName(), consumer: consumer, autoAck: !configuration.RabbitMQ.ManualAck ); // while (!cancellationToken.IsCancellationRequested) { await Task.Delay(1000, cancellationToken); } } /// /// Overriding Stop Action ... /// /// /// public override async Task StopAsync(CancellationToken cancellationToken) { // channel.Close(); channel.Dispose(); connection.Close(); connection.Dispose(); // await base.StopAsync(cancellationToken); } /// /// Dispose Implementation ... /// public override void Dispose() { // channel.Dispose(); connection.Dispose(); GC.SuppressFinalize(this); base.Dispose(); } // #region Private ... private string GetQueueName() { // var result = string.Empty; if (!configuration.RabbitMQ.Queue.IsNullOrEmpty()) { result = configuration.RabbitMQ.Queue; } // if (result.IsNullOrEmpty()) { // var digits = Guid.NewGuid().ToString().GetDigits(); result = $"{configuration.RabbitMQ.Exchange}[{digits}]"; } // return result; } private void SetupConnection() { var factory = new ConnectionFactory { DispatchConsumersAsync = true, Port = configuration.GetRabbitMQPort(), HostName = configuration.GetRabbitMQHost(), UserName = configuration.RabbitMQ.Username, Password = configuration.RabbitMQ.Password, NetworkRecoveryInterval = TimeSpan.FromSeconds( configuration.RabbitMQ.NetworkRecoveryIntervalSeconds ), VirtualHost = configuration.RabbitMQ.VirtualHost, AutomaticRecoveryEnabled = configuration.RabbitMQ.AutomaticRecoveryEnabled, }; // connection = factory.CreateConnection(); channel = connection.CreateModel(); } private void DeclareTopology() { // channel.ExchangeDeclare( arguments: null, exchange: configuration.RabbitMQ.Exchange, durable: configuration.RabbitMQ.ExchangeDurable, autoDelete: configuration.RabbitMQ.ExchangeAutoDelete, type: configuration.RabbitMQ.ExchangeType.GetStringValue() ); // var queueName = GetQueueName(); // channel.QueueDeclare( arguments: null, queue: queueName, durable: configuration.RabbitMQ.QueueDurable, exclusive: configuration.RabbitMQ.QueueExclusive, autoDelete: configuration.RabbitMQ.QueueAutoDelete ); // channel.QueueBind( arguments: null, queue: queueName, exchange: configuration.RabbitMQ.Exchange, routingKey: configuration.RabbitMQ.RoutingKey ); } #endregion } }