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(); } }
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); } }
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); } }
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); } }
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; } }
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; } }
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 } }
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); } } }
/// <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); }
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); }