Example #1
0
        /// <summary>
        ///
        /// <para>CustomSubscribe:</para>
        ///
        /// <para>Subscribes to given custom topic</para>
        ///
        /// <para>Check <seealso cref="IBPubSubServiceInterface.CustomSubscribe"/> for detailed documentation</para>
        ///
        /// </summary>
        public bool CustomSubscribe(
            string _CustomTopic,
            Action <string, string> _OnMessage,
            Action <string> _ErrorMessageAction = null, bool _SubscribeSingleMessage = false)
        {
            if (_CustomTopic != null && _CustomTopic.Length > 0 && _OnMessage != null)
            {
                FailoverCheck();
                try
                {
                    RedisConnection.GetSubscriber().Subscribe(
                        _CustomTopic,
                        (RedisChannel Channel, RedisValue Value) =>
                    {
                        if (UniqueMessageDeliveryEnsurer != null)
                        {
                            var Message = Value.ToString();

                            UniqueMessageDeliveryEnsurer.Subscribe_ClearAndExtractTimestampFromMessage(ref Message, out string TimestampHash);

                            if (UniqueMessageDeliveryEnsurer.Subscription_EnsureUniqueDelivery(Channel, TimestampHash, _ErrorMessageAction))
                            {
                                _OnMessage?.Invoke(Channel, Message);
                            }
                        }
                        else
                        {
                            _OnMessage?.Invoke(Channel, Value.ToString());
                        }
                    });
Example #2
0
        /// <summary>
        ///
        /// <para>CustomSubscribe:</para>
        ///
        /// <para>Subscribes to given custom topic</para>
        ///
        /// <para>Check <seealso cref="IBPubSubServiceInterface.CustomSubscribe"/> for detailed documentation</para>
        ///
        /// </summary>
        public bool CustomSubscribe(string _CustomTopic, Action <string, string> _OnMessage, Action <string> _ErrorMessageAction = null, bool _SubscribeSingleMessage = false)
        {
            if (_CustomTopic != null && _CustomTopic.Length > 0 && _OnMessage != null && BUtility.CalculateStringMD5(_CustomTopic, out string TopicMD5, _ErrorMessageAction))
            {
                if (EnsureQueueExists(TopicMD5, out string QueueUrl, _ErrorMessageAction))
                {
                    var SubscriptionCancellationVar = new BValue <bool>(false, EBProducerStatus.MultipleProducer);
                    var SubscriptionThread          = new Thread(() =>
                    {
                        Thread.CurrentThread.IsBackground = true;

                        while (!SubscriptionCancellationVar.Get())
                        {
                            ReceiveMessageResponse Response;
                            try
                            {
                                using (var ReceiveMessageTask = SQSClient.ReceiveMessageAsync(QueueUrl))
                                {
                                    ReceiveMessageTask.Wait();
                                    Response = ReceiveMessageTask.Result;
                                }
                            }
                            catch (Exception e)
                            {
                                Response = null;
                                _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace);
                                if (e.InnerException != null && e.InnerException != e)
                                {
                                    _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                                }
                            }

                            if (Response == null || Response.Messages == null || Response.Messages.Count == 0)
                            {
                                Thread.Sleep(1000);
                                continue;
                            }

                            var AckDictionary = new Dictionary <string, string>();

                            foreach (var MessageContainer in Response.Messages)
                            {
                                if (MessageContainer != null)
                                {
                                    if (!AckDictionary.ContainsKey(MessageContainer.MessageId))
                                    {
                                        AckDictionary.Add(MessageContainer.MessageId, MessageContainer.ReceiptHandle);
                                    }

                                    string Data = MessageContainer.Body;

                                    if (UniqueMessageDeliveryEnsurer != null)
                                    {
                                        UniqueMessageDeliveryEnsurer.Subscribe_ClearAndExtractTimestampFromMessage(ref Data, out string TimestampHash);

                                        if (UniqueMessageDeliveryEnsurer.Subscription_EnsureUniqueDelivery(_CustomTopic, TimestampHash, _ErrorMessageAction))
                                        {
                                            _OnMessage?.Invoke(_CustomTopic, Data);
                                        }
                                    }
                                    else
                                    {
                                        _OnMessage?.Invoke(_CustomTopic, Data);
                                    }
                                }
                            }

                            var AckArray = new List <DeleteMessageBatchRequestEntry>();
                            foreach (var Current in AckDictionary)
                            {
                                AckArray.Add(new DeleteMessageBatchRequestEntry(Current.Key, Current.Value));
                            }

                            try
                            {
                                using (var DeleteMessageBatchTask = SQSClient.DeleteMessageBatchAsync(QueueUrl, AckArray))
                                {
                                    DeleteMessageBatchTask.Wait();
                                }
                            }
                            catch (Exception e)
                            {
                                _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace);
                                if (e.InnerException != null && e.InnerException != e)
                                {
                                    _ErrorMessageAction?.Invoke("BPubSubServiceAWS->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                                }
                            }
                        }
                    });
                    SubscriptionThread.Start();

                    lock (SubscriberThreadsDictionaryLock)
                    {
                        SubscriberThreadsDictionary.Add(_CustomTopic, new BTuple <Thread, BValue <bool> >(SubscriptionThread, SubscriptionCancellationVar));
                    }
                    return(true);
                }
            }
            return(false);
        }
Example #3
0
        /// <summary>
        ///
        /// <para>CustomSubscribe:</para>
        ///
        /// <para>Subscribes to given custom topic</para>
        ///
        /// <para>Check <seealso cref="IBPubSubServiceInterface.CustomSubscribe"/> for detailed documentation</para>
        ///
        /// </summary>
        public bool CustomSubscribe(
            string _CustomTopic,
            Action <string, string> _OnMessage,
            Action <string> _ErrorMessageAction = null, bool _SubscribeSingleMessage = false)
        {
            if (_CustomTopic != null && _CustomTopic.Length > 0 && _OnMessage != null)
            {
                _CustomTopic = GetGoogleFriendlyTopicName(_CustomTopic);

                if (GetSubscriber(out SubscriberServiceApiClient APIClientVar, out SubscriptionName SubscriptionNameVar, _CustomTopic, _ErrorMessageAction))
                {
                    var SubscriptionCancellationVar = new BValue <bool>(false, EBProducerStatus.MultipleProducer);
                    var SubscriptionThread          = new Thread(() =>
                    {
                        Thread.CurrentThread.IsBackground = true;

                        while (!SubscriptionCancellationVar.Get())
                        {
                            PullResponse Response = null;
                            try
                            {
                                Response = APIClientVar.Pull(SubscriptionNameVar, true, 1000);
                            }
                            catch (Exception e)
                            {
                                if (e is RpcException && (e as RpcException).StatusCode == StatusCode.DeadlineExceeded)
                                {
                                    Thread.Sleep(1000);
                                    continue;
                                }

                                Response = null;

                                _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace);
                                if (e.InnerException != null && e.InnerException != e)
                                {
                                    _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                                }
                            }

                            if (Response == null || Response.ReceivedMessages == null || !Response.ReceivedMessages.Any())
                            {
                                Thread.Sleep(1000);
                                continue;
                            }

                            var MessageContainers = Response.ReceivedMessages.ToArray();
                            if (MessageContainers != null && MessageContainers.Length > 0)
                            {
                                var AckArray = new List <string>();

                                foreach (var MessageContainer in MessageContainers)
                                {
                                    if (MessageContainer != null)
                                    {
                                        if (!AckArray.Contains(MessageContainer.AckId))
                                        {
                                            AckArray.Add(MessageContainer.AckId);
                                        }

                                        string Topic = GetTopicNameFromGoogleFriendlyName(_CustomTopic);
                                        string Data  = MessageContainer.Message.Data.ToStringUtf8();

                                        if (UniqueMessageDeliveryEnsurer != null)
                                        {
                                            UniqueMessageDeliveryEnsurer.Subscribe_ClearAndExtractTimestampFromMessage(ref Data, out string TimestampHash);

                                            if (UniqueMessageDeliveryEnsurer.Subscription_EnsureUniqueDelivery(Topic, TimestampHash, _ErrorMessageAction))
                                            {
                                                _OnMessage?.Invoke(Topic, Data);
                                            }
                                        }
                                        else
                                        {
                                            _OnMessage?.Invoke(Topic, Data);
                                        }
                                    }
                                }

                                try
                                {
                                    APIClientVar.Acknowledge(SubscriptionNameVar, AckArray);
                                }
                                catch (Exception e)
                                {
                                    if (e is RpcException && (e as RpcException).Status.StatusCode == StatusCode.InvalidArgument)
                                    {
                                        //That is fine, probably due to previous subscriptions
                                    }
                                    else
                                    {
                                        _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace);
                                        if (e.InnerException != null && e.InnerException != e)
                                        {
                                            _ErrorMessageAction?.Invoke("BPubSubServiceGC->CustomSubscribe->Inner: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                                        }
                                    }
                                }
                            }
                        }
                    });
                    SubscriptionThread.Start();

                    lock (SubscriberThreadsDictionaryLock)
                    {
                        SubscriberThreadsDictionary.Add(SubscriptionNameVar, new BTuple <Thread, BValue <bool> >(SubscriptionThread, SubscriptionCancellationVar));
                    }
                    return(true);
                }
            }
            return(false);
        }
Example #4
0
        public bool CustomSubscribe(string _CustomTopic, Action <string, string> _OnMessage, Action <string> _ErrorMessageAction = null, bool _SubscribeSingleMessage = false)
        {
            if (_CustomTopic != null && _CustomTopic.Length > 0 &&
                _OnMessage != null)
            {
                _CustomTopic = GetAzureFriendlyTopicName(_CustomTopic);

                if (EnsureTopicExists(_CustomTopic, out ITopicClient _TopicClient, _ErrorMessageAction))
                {
                    if (EnsureSubscriptionExists(_CustomTopic, _TopicClient, out Microsoft.Azure.ServiceBus.ISubscriptionClient _SubscriptionClient, _ErrorMessageAction))
                    {
                        var SubscriptionCancellationVar = new BValue <bool>(false, EBProducerStatus.MultipleProducer);
                        var SubscriptionThread          = new Thread(() =>
                        {
                            Thread.CurrentThread.IsBackground = true;
                            try
                            {
                                // Define exception receiver handler
                                Func <ExceptionReceivedEventArgs, Task> ExceptionReceiverHandler = (ExceptionReceivedEventArgs _EventArgs) =>
                                {
                                    _ErrorMessageAction?.Invoke($"BPubSubServiceAzure->CustomSubscribe->ExceptionReceiverHandler: {_EventArgs.Exception.Message}, Action: {_EventArgs.ExceptionReceivedContext.Action}, EntityPath: {_EventArgs.ExceptionReceivedContext.EntityPath}, Endpoint: {_EventArgs.ExceptionReceivedContext.Endpoint}, ClientId: {_EventArgs.ExceptionReceivedContext.ClientId}, Trace: {_EventArgs.Exception.StackTrace}");

                                    RemoveSubscriberThread(_CustomTopic);
                                    if (!_SubscriptionClient.IsClosedOrClosing)
                                    {
                                        using (var CloseSubscriptionTask = _SubscriptionClient.CloseAsync())
                                        {
                                            CloseSubscriptionTask.Wait();
                                        }
                                    }

                                    return(Task.CompletedTask);
                                };

                                // Configure the message handler options in terms of exception handling, number of concurrent messages to deliver, etc.
                                var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceiverHandler)
                                {
                                    // Maximum number of concurrent calls to the callback ProcessMessagesAsync(), set to 1 for simplicity.
                                    // Set it according to how many messages the application wants to process in parallel.
                                    MaxConcurrentCalls = 1,

                                    // Indicates whether the message pump should automatically complete the messages after returning from user callback.
                                    // False below indicates the complete operation is handled by the user callback as in ProcessMessagesAsync().
                                    AutoComplete = false
                                };

                                // Register the function that processes messages.
                                _SubscriptionClient.RegisterMessageHandler(async(Message MessageContainer, CancellationToken token) =>
                                {
                                    if (MessageContainer != null)
                                    {
                                        string Topic = GetTopicNameFromAzureFriendlyName(_CustomTopic);
                                        string Data  = Encoding.UTF8.GetString(MessageContainer.Body);

                                        if (MessageContainer.Label != null &&
                                            MessageContainer.Label.Equals(_CustomTopic))
                                        {
                                            _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe: Received [Internal] pub/sub message.");
                                        }
                                        else
                                        {
                                            _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe: Received [StorageAccount] pub/sub message.");
                                        }

                                        if (UniqueMessageDeliveryEnsurer != null)
                                        {
                                            UniqueMessageDeliveryEnsurer.Subscribe_ClearAndExtractTimestampFromMessage(ref Data, out string TimestampHash);

                                            if (UniqueMessageDeliveryEnsurer.Subscription_EnsureUniqueDelivery(Topic, TimestampHash, _ErrorMessageAction))
                                            {
                                                _OnMessage?.Invoke(Topic, Data);
                                                RemoveSubscriberThread(_CustomTopic);
                                                if (!_SubscriptionClient.IsClosedOrClosing)
                                                {
                                                    await _SubscriptionClient.CloseAsync();
                                                }
                                            }
                                        }
                                        else
                                        {
                                            _OnMessage?.Invoke(Topic, Data);
                                        }

                                        await _SubscriptionClient.CompleteAsync(MessageContainer.SystemProperties.LockToken);

                                        if (_SubscribeSingleMessage)
                                        {
                                            RemoveSubscriberThread(_CustomTopic);
                                            if (!_SubscriptionClient.IsClosedOrClosing)
                                            {
                                                await _SubscriptionClient.CloseAsync();
                                            }
                                        }
                                    }
                                }, messageHandlerOptions);
                            }
                            catch (Exception e)
                            {
                                _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe: " + e.Message + ", Trace: " + e.StackTrace);
                                if (e.InnerException != null && e.InnerException != e)
                                {
                                    _ErrorMessageAction?.Invoke("BPubSubServiceAzure->CustomSubscribe->InnerException: " + e.InnerException.Message + ", Trace: " + e.InnerException.StackTrace);
                                }

                                RemoveSubscriberThread(_CustomTopic);
                                if (!_SubscriptionClient.IsClosedOrClosing)
                                {
                                    using (var CloseSubscriptionTask = _SubscriptionClient.CloseAsync())
                                    {
                                        CloseSubscriptionTask.Wait();
                                    }
                                }
                            }

                            while (!SubscriptionCancellationVar.Get())
                            {
                                //Wait until delete
                                Thread.Sleep(500);
                            }

                            if (!_SubscriptionClient.IsClosedOrClosing)
                            {
                                using (var CloseSubscriptionTask = _SubscriptionClient.CloseAsync())
                                {
                                    CloseSubscriptionTask.Wait();
                                }
                            }
                        });
                        SubscriptionThread.Start();

                        lock (SubscriberThreadsDictionaryLock)
                        {
                            SubscriberThreadsDictionary.Add(_CustomTopic, new BTuple <Thread, BValue <bool> >(SubscriptionThread, SubscriptionCancellationVar));
                        }
                        return(true);
                    }
                }
            }
            return(false);
        }