public RabbitContext(MessageQueueSettings settings, ILogger logger) { var rabbitConnFactory = new ConnectionFactory { HostName = settings.Hostname, UserName = settings.Username, Password = settings.Password, RequestedHeartbeat = 60, AutomaticRecoveryEnabled = true, TopologyRecoveryEnabled = true, NetworkRecoveryInterval = TimeSpan.FromSeconds(5) }; _connection = rabbitConnFactory.CreateConnection(); _logger = logger; using (var channel = _connection.CreateModel()) { channel.ExchangeDeclare(exchange: ExchangeName, type: ExchangeType.Topic, durable: true, autoDelete: false, arguments: null); channel.QueueDeclare(queue: QueueName, durable: true, exclusive: false, autoDelete: false); channel.QueueBind(QueueName, ExchangeName, RoutingKey, null); } }
// http://stackoverflow.com/questions/16658915/reactive-extensions-concurrency-within-the-subscriber // https://social.msdn.microsoft.com/Forums/en-US/6ef0caba-709d-450a-830d-8fc80f0a815d/the-rx-serialization-guarantee?forum=rx private static async Task RabbitMqObserver(ILogger logger, CancellationToken cancellationToken = default(CancellationToken)) { logger.LogInformation("ConcurrencyLevel: {concurrencyLevel}", ConcurrencyLevel); Sleep(logger, TimeSpan.FromSeconds(10), "to let RabbitMQ start up"); var config = ConfigBuilder.Build(); var settings = new MessageQueueSettings(); ConfigurationBinder.Bind(config.GetSection("MessageQueue"), settings); using (var context = new RabbitContext(settings, logger)) { var publisher = Task.Run(async() => { do { context.Publish(new Bogus.Faker().Lorem.Sentence(20)); await Task.Delay(TimeSpan.FromMilliseconds(100)); } while (cancellationToken.IsCancellationRequested == false); }); var subscriber = Task.Run(async() => { Action <IMessage <string> > onNextImpl = message => { logger.LogDebug("Started handling {messageId}", message.Id); try { Thread.Sleep(3000); Console.WriteLine(message.GetContent()); message.CompleteAsync().Wait(); } catch (Exception ex) { logger.LogError(0, ex, "Error while handling {messageId}", message.Id); message.AbandonAsync().Wait(); } }; // Action to invoke for each element in the observable sequence. Action <IMessage <string> > onNext = message => Task.Run(() => onNextImpl(message)); // Action to invoke upon exceptional termination of the observable sequence Action <Exception> onError = ex => { logger.LogError(0, ex, "Exceptional termination of the observable sequence"); }; // Action to invoke upon graceful termination of the observable sequence. Action onCompleted = () => { logger.LogDebug("Graceful termination of the observable sequence"); }; using (var subscription = context.CreateSubscription()) using (subscription.Observable.ObserveOn(NewThreadScheduler.Default).Subscribe(onNext, onError, onCompleted)) { await SleepTillCancelledAsync(cancellationToken); } }); await Task.WhenAll(publisher, subscriber); } }