internal void DispatchBasicReturn(ushort replyCode, string replyText, string exchange, string routingKey, int bodySize, BasicProperties properties, BaseLightStream ringBufferStream) { var ev = this.MessageUndeliveredHandler; var marker = new RingBufferPositionMarker(ringBufferStream); try { if (ev != null) { var inst = new UndeliveredMessage { bodySize = bodySize, stream = bodySize == 0 ? EmptyStream : ringBufferStream, properties = properties, routingKey = routingKey, replyCode = replyCode, replyText = replyText, exchange = exchange }; ev(inst); } } finally { marker.EnsureConsumed(bodySize); } }
public RingBufferPositionMarker(BaseLightStream untypedStream) { _ringBuffer = null; _mbStreamWrapper = untypedStream as MultiBodyStreamWrapper; _start = 0; var adapter = untypedStream as RingBufferStreamAdapter; if (adapter != null) { _ringBuffer = adapter._ringBuffer; _start = _ringBuffer.GlobalReadPos; } }
internal void DispatchDeliveredMessage( string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey, int bodySize, BasicProperties properties, BaseLightStream lightStream) { BasicConsumerSubscriptionInfo consumer; if (!_consumerSubscriptions.TryGetValue(consumerTag, out consumer)) { // received msg but nobody was subscribed to get it (?) LogAdapter.LogWarn(LogSource, "Received message without a matching subscription. Discarding. " + "Exchange: " + exchange + " routing: " + routingKey + " consumer tag: " + consumerTag + " and channel " + this.ChannelNumber); // Ensure moved cursor ahead var marker = new RingBufferPositionMarker(lightStream); marker.EnsureConsumed(bodySize); return; } var delivery = new MessageDelivery { bodySize = bodySize, properties = properties, routingKey = routingKey, deliveryTag = deliveryTag + this._deliveryTagOffset, // adds tag offset redelivered = redelivered, }; var mode = consumer.Mode; var cb = consumer.Callback; var consumerInstance = consumer._consumer; if (mode == ConsumeMode.SingleThreaded) { // run with scissors, we're letting // the user code mess with the ring buffer in the name of performance delivery.stream = bodySize == 0 ? EmptyStream : lightStream; // upon return it's assumed the user has consumed from the stream and is done with it var marker = new RingBufferPositionMarker(lightStream); try { if (cb != null) { cb(delivery).GetAwaiter().GetResult(); } else { consumerInstance.Consume(delivery).GetAwaiter().GetResult(); } } finally { if (!delivery.TakenOver) { delivery.Dispose(); } // fingers crossed the user cloned the buffer if she needs it later marker.EnsureConsumed(bodySize); } } else { // parallel mode. it cannot hold the frame handler, so we copy the buffer (yuck) and move forward if (mode == ConsumeMode.ParallelWithBufferCopy || mode == ConsumeMode.SerializedWithBufferCopy) { delivery.stream = delivery.bodySize == 0 ? EmptyStream : lightStream.CloneStream(bodySize); } if (mode == ConsumeMode.SerializedWithBufferCopy) // Posts to a thread { if (consumer._consumerThread == null) { // Initialization. safe since this delivery call always happen from the same thread consumer._receivedMessages = new ConcurrentQueue <MessageDelivery>(); consumer._messageAvailableEv = new AutoResetEvent(false); consumer._consumerThread = ThreadFactory.BackgroundThread(SerializedDelivery, "Delivery_" + consumer.ConsumerTag, consumer); } consumer._receivedMessages.Enqueue(delivery); consumer._messageAvailableEv.Set(); } else if (mode == ConsumeMode.ParallelWithBufferCopy) // Posts to TaskScheduler { new Task(async state => { var tuple = (Tuple <MessageDelivery, Func <MessageDelivery, Task>, IQueueConsumer, Channel>)state; var delivery1 = tuple.Item1; var cb1 = tuple.Item2; var conInstance = tuple.Item3; try { if (cb1 != null) { await cb1(delivery1).ConfigureAwait(false); } else { await conInstance.Consume(delivery1).ConfigureAwait(false); } } catch (Exception e) { if (LogAdapter.IsErrorEnabled) { LogAdapter.LogError(LogSource, "Error processing message (user code)", e); } } finally { if (!delivery1.TakenOver) { delivery1.Dispose(); } } }, Tuple.Create(delivery, cb, consumerInstance, this)) // tuple avoids the closure capture // Start task in the given scheduler .Start(_schedulerToDeliverMessages); } } }