示例#1
0
        internal void UnblockAllChannels()
        {
            LogAdapter.LogWarn(LogSource, "Unblocking all channels");

            foreach (var channel in _channels)
            {
                if (channel == null)
                {
                    continue;
                }
                channel.UnblockChannel();
            }

            var ev = this.ConnectionUnblocked;

            if (ev != null)
            {
                ev();
            }
        }
示例#2
0
        internal void BlockAllChannels(string reason)
        {
            LogAdapter.LogWarn(LogSource, "Blocking all channels: " + reason);

            foreach (var channel in _channels)
            {
                if (channel == null)
                {
                    continue;
                }
                channel.BlockChannel(reason);
            }

            var ev = this.ConnectionBlocked;

            if (ev != null)
            {
                ev(reason);
            }
        }
示例#3
0
        private void SerializedDelivery(BasicConsumerSubscriptionInfo consumer)
        {
            while (!consumer._cancelThread && !this.IsClosed)
            {
                consumer._messageAvailableEv.WaitOne();

                MessageDelivery delivery;
                while (consumer._receivedMessages.TryDequeue(out delivery))
                {
                    try
                    {
                        if (consumer.Callback != null)
                        {
                            consumer.Callback(delivery).ConfigureAwait(false).GetAwaiter().GetResult();
                            continue;
                        }

                        consumer._consumer.Consume(delivery).ConfigureAwait(false).GetAwaiter().GetResult();
                    }
                    catch (Exception ex)
                    {
                        if (LogAdapter.IsErrorEnabled)
                        {
                            LogAdapter.LogError(LogSource, "Consumer error. Tag " + consumer.ConsumerTag, ex);
                        }
                    }
                    finally
                    {
                        if (!delivery.TakenOver)
                        {
                            delivery.Dispose();
                        }
                    }
                }
            }

            if (LogAdapter.ExtendedLogEnabled)
            {
                LogAdapter.LogDebug(LogSource, "Consumer exiting. Tag " + consumer.ConsumerTag);
            }
        }
示例#4
0
        private void SerializedDelivery(BasicConsumerSubscriptionInfo consumer)
        {
            while (!consumer._cancelThread && !this.IsClosed)
            {
                consumer._messageAvailableEv.WaitOne();

                MessageDelivery delivery;
                while (consumer._receivedMessages.TryDequeue(out delivery))
                {
                    try
                    {
                        if (consumer.Callback != null)
                        {
                            consumer.Callback(delivery).Wait();
                            continue;
                        }

                        consumer._consumer.Consume(delivery).Wait();
                    }
                    catch (Exception ex)
                    {
                        LogAdapter.LogError("Channel", "Consumer error. Tag " + consumer.ConsumerTag, ex);
                    }
                    finally
                    {
                        this.Return(delivery.properties);

                        if (delivery.bodySize != 0)
                        {
                            delivery.stream.Dispose();
                        }
                    }
                }
            }

            if (LogAdapter.ExtendedLogEnabled)
            {
                LogAdapter.LogDebug("Channel", "Consumer exiting. Tag " + consumer.ConsumerTag);
            }
        }
示例#5
0
        public static async Task <IConnection> Connect(IEnumerable <string> hostnames,
                                                       string vhost      = "/", string username        = "******",
                                                       string password   = "******", int port           = 5672,
                                                       bool autoRecovery = true, string connectionName = null)
        {
            var conn = new Connection();

            try
            {
                foreach (var hostname in hostnames)
                {
                    var successful =
                        await conn.Connect(hostname, vhost,
                                           username, password, port, connectionName,
                                           throwOnError : false).ConfigureAwait(false);

                    if (successful)
                    {
                        LogAdapter.LogWarn("ConnectionFactory", "Selected " + hostname);

                        return(autoRecovery ?
                               (IConnection) new RecoveryEnabledConnection(hostnames, conn) :
                               conn);
                    }
                }

                // TODO: collect exceptions and add them to aggregateexception:
                throw new AggregateException("Could not connect to any of the provided hosts");
            }
            catch (Exception e)
            {
                LogAdapter.LogError("ConnectionFactory", "Connection error", e);

                conn.Dispose();
                throw;
            }
        }
示例#6
0
        public static async Task <IConnection> Connect(string hostname,
                                                       string vhost    = "/", string username = "******",
                                                       string password = "******", int port    = 5672,
                                                       AutoRecoverySettings recoverySettings = null, string connectionName = null,
                                                       int maxChannels = 30, ushort heartbeat = 0)
        {
            recoverySettings = recoverySettings ?? AutoRecoverySettings.Off;
            connectionName   = connectionName ?? DefaultConnectionName;

            var conn = new Connection();

            try
            {
                await conn
                .Connect(hostname, vhost, username, password, port, connectionName, heartbeat, throwOnError : true)
                .ConfigureAwait(false);

                conn.SetMaxChannels(maxChannels);

                if (LogAdapter.ExtendedLogEnabled)
                {
                    LogAdapter.LogDebug(LogSource, "Connected to " + hostname + ":" + port);
                }

                return(recoverySettings.Enabled ? (IConnection) new RecoveryEnabledConnection(hostname, conn, recoverySettings) : conn);
            }
            catch (Exception e)
            {
                if (LogAdapter.IsErrorEnabled)
                {
                    LogAdapter.LogError(LogSource, "Connection error: " + hostname + ":" + port, e);
                }

                conn.Dispose();
                throw;
            }
        }
示例#7
0
        internal void CloseAllChannels(bool initiatedByServer, AmqpError error)
        {
            if (LogAdapter.IsDebugEnabled)
            {
                LogAdapter.LogDebug(LogSource, "Closing all channels");
            }

            if (_channels == null)
            {
                return;
            }

            foreach (var channel in _channels)
            {
                if (channel == null)
                {
                    continue;
                }

#pragma warning disable 4014
                channel._io.InitiateCleanClose(initiatedByServer, error);
#pragma warning restore 4014
            }
        }
示例#8
0
        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);
                }
            }
        }
示例#9
0
        /// <summary>
        /// The request message is expected to have multiple receivers, and multiple replies.
        /// The replies will be aggregated and returned, respecting up to a minimum set by minExpectedReplies, and
        /// if unsuccessful a timeout error will be thrown.
        /// </summary>
        public Task <IEnumerable <MessageDelivery> > CallAggregate(string exchange, string routing,
                                                                   BasicProperties properties,
                                                                   ArraySegment <byte> buffer, int minExpectedReplies, bool runContinuationsAsynchronously = true)
        {
            if (!_operational)
            {
                throw new Exception("Can't make RPC call when connection in recovery");
            }

            _semaphoreSlim.Wait();

            uint correlationId;
            long pos;
            var  tcs = SecureSpotAndUniqueCorrelationId(runContinuationsAsynchronously, exchange, routing, out pos, out correlationId);

            if (tcs == null)
            {
                _semaphoreSlim.Release();

                // NOTE: If our use of semaphore is correct, this should never happen:
                LogAdapter.LogError(LogSource, "Maxed calls: " + _maxConcurrentCalls);
                throw new Exception("reached max calls");
            }

            var cookie = tcs.Task.Id;
            var state  = _pendingAggregationState[pos];

            lock (state)             // bad, but chances of s*** happening are too high
            {
                Interlocked.Exchange(ref state.waitingCount, minExpectedReplies);
                Interlocked.Exchange(ref state.cookie, cookie);
                state.received.Clear();
            }

            try
            {
                var prop = (properties == null || properties == BasicProperties.Empty) ? _channel.RentBasicProperties() : properties;

                prop.CorrelationId = BuildFullCorrelation(cookie, correlationId);                 // correlationId + SeparatorStr + cookie;
                prop.ReplyTo       = _replyQueueName.Name;

                // TODO: confirm this doesnt cause more overhead to rabbitmq
                if (_timeoutInMs.HasValue)
                {
//					prop.Expiration = _timeoutInMs.ToString();
                }

                _channel.BasicPublishFast(exchange, routing, true, prop, buffer);
            }
            catch (Exception ex)
            {
                if (ReleaseSpot(pos, cookie))
                {
                    _semaphoreSlim.Release();
                }

                tcs.TrySetException(ex);
            }

            return(tcs.Task);
        }
示例#10
0
        protected override Task OnReplyReceived(MessageDelivery delivery)
        {
            long pos    = 0;
            int  cookie = 0;

            try
            {
                uint correlationIdVal;
                GetPosAndCookieFromCorrelationId(delivery.properties.CorrelationId,
                                                 out correlationIdVal, out pos, out cookie);

                var state     = _pendingAggregationState[pos];
                var completed = false;
                IEnumerable <MessageDelivery> aggreDeliveries = null;
                lock (state)
                {
                    if (state.cookie != cookie)
                    {
                        // most likely this is a late reply for something that has already timeout
                        return(Task.CompletedTask);
                    }

                    completed = Interlocked.Decrement(ref state.waitingCount) == 0;

                    if (_mode == ConsumeMode.SingleThreaded)
                    {
                        state.received.Add(delivery.SafeClone());
                    }
                    else
                    {
                        delivery.TakenOver = true;
                        state.received.Add(delivery);
                    }

                    if (completed)
                    {
                        aggreDeliveries = state.received.ToArray();                         // needs extra copy

                        // reset cookie
                        Interlocked.Exchange(ref state.cookie, 0);
                    }
                }

                if (!completed)                 // still waiting for more replies
                {
                    return(Task.CompletedTask);
                }


                // Completed!

                var item = _pendingCalls[pos];
                TaskCompletionSource <IEnumerable <MessageDelivery> > tcs;

                if (item.cookie != cookie || (tcs = Interlocked.Exchange(ref item.tcs, null)) == null)
                {
                    // the helper was disposed and the task list was drained.
                    // or the call timeout'ed previously
                    return(Task.CompletedTask);
                }

                if (ReleaseSpot(pos, cookie))
                {
                    _semaphoreSlim.Release();
                    tcs.TrySetResult(aggreDeliveries);
                }
            }
            catch (Exception error)
            {
                if (ReleaseSpot(pos, cookie))
                {
                    _semaphoreSlim.Release();
                }

                if (LogAdapter.IsErrorEnabled)
                {
                    LogAdapter.LogError(LogSource, "Error on OnReplyReceived", error);
                }
            }

            return(Task.CompletedTask);
        }