Beispiel #1
0
        async Task RunAsync()
        {
            await Task.Yield();

            var prefixDot = CachePrefix + ".";

            try
            {
                for (;;)
                {
                    var msg = _input.Read(Properties.All, TimeSpan.Zero) ?? await _input.ReadAsync(Properties.All);

                    if (msg.Label.StartsWith(prefixDot, StringComparison.OrdinalIgnoreCase))
                    {
                        switch ((MessageCacheAction)msg.AppSpecific)
                        {
                        case MessageCacheAction.Read:
                            SendLastValue(msg);
                            break;

                        case MessageCacheAction.Remove:
                            Invalidate(msg);
                            break;
                        }
                    }
                    else if (msg.Label.Equals(CachePrefix, StringComparison.OrdinalIgnoreCase))
                    {
                        switch ((MessageCacheAction)msg.AppSpecific)
                        {
                        case MessageCacheAction.ListKeys:
                            SendKeyList(msg);
                            break;

                        case MessageCacheAction.Clear:
                            ClearCache();
                            break;
                        }
                    }
                    else
                    {
                        StoreLastValue(msg);
                    }
                }
            }
            catch (ObjectDisposedException)
            {
                // Stop was called
            }
            catch (QueueException ex) when(ex.ErrorCode == ErrorCode.OperationCanceled)
            {
                // Stop was called
            }
        }
        /// <summary>Report any failure to send to destination queues</summary>
        async Task AdminTask()
        {
            await Task.Yield();

            var props = Properties.Class | Properties.DestinationQueue | Properties.Label;

            try
            {
                for (;;)
                {
                    var msg = _adminReader.Read(props, TimeSpan.Zero) ?? await _adminReader.ReadAsync(props);

                    var ack = msg.Acknowledgement();
                    switch (ack)
                    {
                    case MessageClass.ReachQueueTimeout:
                    case MessageClass.AccessDenied:
                    case MessageClass.BadDestinationQueue:
                    case MessageClass.BadEncryption:
                    case MessageClass.BadSignature:
                    case MessageClass.CouldNotEncrypt:
                    case MessageClass.HopCountExceeded:
                    case MessageClass.NotTransactionalMessage:
                    case MessageClass.NotTransactionalQueue:
                    case MessageClass.Deleted:
                    case MessageClass.QueueDeleted:
                    case MessageClass.QueuePurged:
                    case MessageClass.QueueExceedQuota:
                    case MessageClass.ReceiveTimeout:
                        Console.Error.WriteLine($"WARNING {ack} sending '{msg.Label}' to {msg.DestinationQueue}");
                        break;
                    }
                }
            }
            catch (QueueException ex) when(ex.ErrorCode == ErrorCode.OperationCanceled)
            {
                // stopped
            }
            catch (ObjectDisposedException)
            {
                // stopped
            }
        }
Beispiel #3
0
        async Task AdminAsync()
        {
            try
            {
                for (;;)
                {
                    const Properties adminProps = Properties.Class | Properties.Id | Properties.Label | Properties.DestinationQueue;
                    var msg = _admin.Read(adminProps, TimeSpan.Zero) ?? await _admin.ReadAsync(adminProps);

                    var ack = msg.Acknowledgement();
                    switch (ack)
                    {
                    case MessageClass.ReachQueueTimeout:
                    case MessageClass.AccessDenied:
                    case MessageClass.BadDestinationQueue:
                    case MessageClass.BadEncryption:
                    case MessageClass.BadSignature:
                    case MessageClass.CouldNotEncrypt:
                    case MessageClass.HopCountExceeded:
                    case MessageClass.NotTransactionalMessage:
                    case MessageClass.NotTransactionalQueue:
                    case MessageClass.Deleted:
                    case MessageClass.QueueDeleted:
                    case MessageClass.QueuePurged:
                    case MessageClass.QueueExceedQuota:
                        Console.Error.WriteLine($"WARNING: message labelled '{msg.Label}' failed to reach '{msg.DestinationQueue}' because {ack}");
                        break;
                    }
                }
            }
            catch (ObjectDisposedException)
            {
                // Stop was called
            }
            catch (QueueException ex) when(ex.ErrorCode == ErrorCode.OperationCanceled)
            {
                // Stop was called
            }
        }
Beispiel #4
0
        async Task RunAsync()
        {
            await Task.Yield();

            try
            {
                for (;;)
                {
                    var msg = _adminQueue.Read(AdminProperties, TimeSpan.Zero) ?? await _adminQueue.ReadAsync(AdminProperties);

                    var ack = msg.Acknowledgement();
                    switch (ack)
                    {
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    case MessageClass.ReachQueue:
                        var tcs = ReachQueueCompletionSource(new Tracking(msg.ResponseQueue, msg.CorrelationId));
                        Task.Run(() => tcs.TrySetResult(ack));     // set result is synchronous by default, make it async
                        break;

                    case MessageClass.ReachQueueTimeout:
                    case MessageClass.AccessDenied:
                    case MessageClass.BadDestinationQueue:
                    case MessageClass.BadEncryption:
                    case MessageClass.BadSignature:
                    case MessageClass.CouldNotEncrypt:
                    case MessageClass.HopCountExceeded:
                    case MessageClass.NotTransactionalMessage:
                    case MessageClass.NotTransactionalQueue:
                    case MessageClass.Deleted:
                    case MessageClass.QueueDeleted:
                    case MessageClass.QueuePurged:
                    case MessageClass.QueueExceedQuota:
                        var tcs1 = ReachQueueCompletionSource(new Tracking(msg.ResponseQueue, msg.CorrelationId));
                        Task.Run(() => tcs1.TrySetException(new AcknowledgmentException(msg.ResponseQueue, ack)));     // set result is synchronous by default, make it async
                        break;

                    case MessageClass.Received:
                        var tcs2 = ReceiveCompletionSource(new Tracking(msg.ResponseQueue, msg.CorrelationId));
                        Task.Run(() => tcs2.TrySetResult(ack));     // set result is synchronous by default, make it async
                        break;

                    case MessageClass.ReceiveTimeout:
                        var tcs3 = ReceiveCompletionSource(new Tracking(msg.ResponseQueue, msg.CorrelationId));
                        Task.Run(() => tcs3.TrySetException(new AcknowledgmentException(msg.ResponseQueue, ack))); // set result is synchronous by default, make it async
                        break;
#pragma warning restore CS4014                                                                                     // Because this call is not awaited, execution of the current method continues before the call is completed
                    }
                }
            }
            catch (QueueException ex) when(ex.ErrorCode == ErrorCode.OperationCanceled)
            {
                // stopped
            }
            catch (ObjectDisposedException)
            {
                // stopped
            }
        }
        /// <summary>Respond to requests to subscribe or unsubscribe</summary>
        /// <remarks>
        /// Add Subscription: label: tag, AppSpecific: Add, ResponseQueue: subscriber identity, Body: UTF-8 subjects, one per line
        /// Set Subscriptions: label: tag, AppSpecific: Set, ResponseQueue: subscriber identity, Body: UTF-8 subjects, one per line
        /// Remove Subscriptions: label: tag, AppSpecific: Remove, ResponseQueue: subscriber identity, Body: UTF-8 subjects, one per line
        /// Clear Subscriptions: label: tag, AppSpecific: Clear, ResponseQueue: subscriber identity
        /// List Subscriptions: label: tag, AppSpecific: List, ResponseQueue: subscriber identity
        /// </remarks>
        async Task SubscriptionLoop()
        {
            await Task.Yield();

            Properties props = Properties.AppSpecific | Properties.Label | Properties.ResponseQueue | Properties.Body;

            try
            {
                for (;;)
                {
                    var msg = _clientRequestReader.Read(props, TimeSpan.Zero) ?? await _clientRequestReader.ReadAsync(props);

                    var    tag           = msg.Label;
                    string responseQueue = msg.ResponseQueue;
                    var    labels        = msg.BodyUTF8()?.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

                    if (responseQueue.Length == 0)
                    {
                        Console.Error.WriteLine("Request with no response queue, ignoring message: " + msg.Id);
                        continue;
                    }

                    PubSubAction action = (PubSubAction)msg.AppSpecific;
                    switch (action)
                    {
                    case PubSubAction.Add:
                        lock (_subscriptions.SyncRoot)
                        {
                            foreach (var l in labels)
                            {
                                _subscriptions.Add(l, responseQueue, tag);
                            }
                        }
                        break;

                    case PubSubAction.Remove:
                        lock (_subscriptions.SyncRoot)
                        {
                            foreach (var l in labels)
                            {
                                _subscriptions.Remove(l, responseQueue, tag);
                            }
                        }
                        break;

                    case PubSubAction.Set:
                        var targetSubs = new HashSet <string>(labels);
                        lock (_subscriptions.SyncRoot)
                        {
                            var currentSubs = _subscriptions.GetSubscriptions(responseQueue, tag);

                            foreach (var l in targetSubs.Where(l => !currentSubs.Contains(l)))
                            {
                                _subscriptions.Add(l, responseQueue, tag);
                            }
                            foreach (var l in currentSubs.Where(l => !targetSubs.Contains(l)))
                            {
                                _subscriptions.Remove(l, responseQueue, tag);
                            }
                        }
                        break;

                    case PubSubAction.Clear:
                        _subscriptions.Clear(responseQueue, tag);
                        break;

                    case PubSubAction.List:
                        HashSet <string> current = _subscriptions.GetSubscriptions(responseQueue, tag);
                        var reply = new Message {
                            AdministrationQueue = _adminQueueFormatName, Label = tag, CorrelationId = msg.Id
                        };
                        reply.BodyUTF8(string.Join(Environment.NewLine, current.OrderBy(l => l)));
                        var q = _responseQueueCache.Open(responseQueue, QueueAccessMode.Send);
                        q.Write(reply);
                        break;

                    default:
                        Console.Error.WriteLine($"Request with invalid {nameof(msg.AppSpecific)} {action}, ignoring request, message id '{msg.Id}' for '{responseQueue}'");
                        break;
                    }
                }
            }
            catch (QueueException ex) when(ex.ErrorCode == ErrorCode.OperationCanceled)
            {
                // stopped
            }
            catch (ObjectDisposedException)
            {
                // stopped
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("ERROR SubscriptionLoop: " + ex);
            }
        }
        /// <summary>Read messages from the input queue and forward to subscribers</summary>
        async Task MulticastInputDispatcher()
        {
            await Task.Yield();

            try
            {
                for (;;)
                {
                    var msg = _inputReader.Read(Properties.All, TimeSpan.Zero) ?? await _inputReader.ReadAsync(Properties.All);

                    // we could avoid the lock by using an immutable collection
                    var subscribers = _subscriptions.GetSubscribers(msg.Label);
                    if (subscribers.Count == 0)
                    {
                        continue;
                    }

                    var fn = string.Join(",", subscribers.Select(s => s.FormatName).Distinct()); // create a multi-element format name
                    var q  = _responseQueueCache.Open(fn, QueueAccessMode.Send);
                    msg.AdministrationQueue = _adminQueueFormatName;
                    q.Write(msg);
                }
            }
            catch (QueueException ex) when(ex.ErrorCode == ErrorCode.OperationCanceled)
            {
                // stopped
            }
            catch (ObjectDisposedException)
            {
                // stopped
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("ERROR MulticastInputDispatcher: " + ex);
            }
        }