/// <summary>
        /// Задача по актуализации
        /// </summary>
        private void Actualize()
        {
            // Убираем из текущих слушателей остановленные
            var stoppedConsumers = this._consumers.Where(x => !x.IsRunning);

            this._consumers.RemoveAll(x => stoppedConsumers.Contains(x));

            var subscriptions = _esbSubscriptionsManager.GetCallbackSubscriptions();
            var allConsumers  = subscriptions.Select(x => new RmqConsumer(_logger, _converter, _connectionFactory, x, DefaultPrefetchCount, useLegacySenders)).ToList();

            // Множество новых слушатей = Текущие подписки - запущенные подписки
            var newConsumers = allConsumers.Except(this._consumers);

            // Множество слушателей на удаление = Запущенные подписки - текущие подписки
            var consumersToDelete = this._consumers.Except(allConsumers);

            foreach (var newConsumer in newConsumers)
            {
                this._consumers.Add(newConsumer);
                newConsumer.Start();
            }

            foreach (var consumerToDelete in consumersToDelete)
            {
                consumerToDelete.Stop();
            }

            // Обновляем данные подписки (на случай если изменился тип callback'а или адрес)
            foreach (var consumer in this._consumers)
            {
                var actualConsumer = allConsumers.First(x => x.Equals(consumer));
                consumer.UpdateSubscription(actualConsumer.Subscription);
            }
        }
        /// <summary>
        /// Метод, выполняющий запуск потоков отправки для каждой подписки.
        /// </summary>
        private void SendMsgsByCallBack()
        {
            try
            {
                // Ищем актуальные подписки, для которых есть сообщения.
                IEnumerable <Subscription> callbackSubscriptions = _subscriptionsManager.GetCallbackSubscriptions().Where(x => GetCurrentMessageCount(x.Client.ID, x.MessageType.ID) > 0);
                try
                {
                    foreach (var subscription in callbackSubscriptions)
                    {
                        SubscriberThreadPool.QueueUserWorkItem(subscription, _scanninWaitEvent, _statistics, _dataService, _logger);
                    }

                    SubscriberThreadPool.CheckForUnActiveSubscribers();
                }
                catch (Exception e)
                {
                    _logger.LogUnhandledException(e, null, "Ошибка при порождении потоков подписчиков через QueueUserWorkItem.");
                }
            }
            catch (Exception e)
            {
                _logger.LogUnhandledException(e, null, "Ошибка при получении активных подписок, отправляемых по Callback.");
            }
        }
예제 #3
0
        /// <summary>
        /// Selects messages from the database that can be sent.
        /// </summary>
        /// <param name="state">Not used.</param>
        private void ScanMessages(object state)
        {
            try
            {
                if (_sendingTasksCount >= MaxTasks)
                {
                    return;
                }

                IEnumerable <Subscription> subscriptions = _subscriptionsManager.GetCallbackSubscriptions();
                if (!subscriptions.Any())
                {
                    return;
                }

                foreach (var clientSubscriptions in subscriptions.GroupBy(s => s.Client))
                {
                    int  currentConnections = 0;
                    int  connectionsLimit   = clientSubscriptions.Key.ConnectionsLimit ?? DefaultConnectionsLimit;
                    Guid clientId           = (KeyGuid)clientSubscriptions.Key.__PrimaryKey;
                    if (!_clientConnections.TryGetValue(clientId, out currentConnections))
                    {
                        _clientConnections.Add(clientId, 0);
                    }

                    if (currentConnections >= connectionsLimit)
                    {
                        continue;
                    }

                    SQLWhereLanguageDef        langDef = SQLWhereLanguageDef.LanguageDef;
                    LoadingCustomizationStruct lcs     = LoadingCustomizationStruct.GetSimpleStruct(typeof(Message), Message.Views.SendingByCallbackView);

                    // All messages for this client by all its active subscriptions
                    Function clientLimitFunction = langDef.GetFunction(langDef.funcOR, clientSubscriptions.Select(s => langDef.GetFunction(
                                                                                                                      langDef.funcAND,
                                                                                                                      langDef.GetFunction(langDef.funcEQ, new VariableDef(langDef.GuidType, Information.ExtractPropertyPath <Message>(m => m.Recipient)), s.Client.__PrimaryKey),
                                                                                                                      langDef.GetFunction(langDef.funcEQ, new VariableDef(langDef.GuidType, Information.ExtractPropertyPath <Message>(m => m.MessageType)), s.MessageType.__PrimaryKey))).ToArray());

                    // Only unsent messages whose sending time has already arrived
                    lcs.LimitFunction = langDef.GetFunction(
                        langDef.funcAND,
                        clientLimitFunction,
                        langDef.GetFunction(langDef.funcEQ, new VariableDef(langDef.BoolType, Information.ExtractPropertyPath <Message>(m => m.IsSending)), false),
                        langDef.GetFunction(langDef.funcLEQ, new VariableDef(langDef.DateTimeType, Information.ExtractPropertyPath <Message>(m => m.SendingTime)), DateTime.Now));

                    // Get no more than we can send
                    lcs.ReturnTop   = connectionsLimit - currentConnections;
                    lcs.ColumnsSort = new[]
                    {
                        new ColumnsSortDef(Information.ExtractPropertyPath <Message>(m => m.Priority), SortOrder.Asc),
                        new ColumnsSortDef(Information.ExtractPropertyPath <Message>(m => m.SendingTime), SortOrder.Asc),
                    };

                    Stopwatch    stopwatch = Stopwatch.StartNew();
                    DataObject[] messages  = _dataService.LoadObjects(lcs);
                    stopwatch.Stop();
                    _statisticsService.NotifyAvgTimeSql(null, (int)stopwatch.ElapsedMilliseconds, $"PrioritySendingManager.ScanMessages(): Load {lcs.ReturnTop} messages for client with name: {clientSubscriptions.Key.Name}.");

                    int index = 0;
                    while (index < messages.Length && TryEnqueue((Message)messages[index]))
                    {
                        index++;
                    }
                }
            }
            catch (Exception exception)
            {
                _logger.LogError("An error occurred while scanning messages.", exception.ToString());
            }
        }
        /// <summary>
        /// Метод отправки сообщений из БД, выполняющийся по таймеру.
        /// </summary>
        /// <param name="state">Состояние, передаваемое при вызове метода таймером.</param>
        private void ScanMessages(object state)
        {
            try
            {
                if (_sendingTasksCount >= MaxTasks)
                {
                    return;
                }

                IEnumerable <Subscription> subscriptions = _subscriptionsManager.GetCallbackSubscriptions().ToList();
                if (!subscriptions.Any())
                {
                    return;
                }

                // Условие, ограничивающее получателя и тип сообщения загружаемых сообщений в соответствии с имеющимися подписками.
                Function[] conditionsList = subscriptions
                                            .Select(
                    s =>
                    _langDef.GetFunction(
                        _langDef.funcAND,
                        _langDef.GetFunction(_langDef.funcEQ, new VariableDef(_langDef.GuidType, Information.ExtractPropertyPath <Message>(x => x.Recipient)), s.Client.__PrimaryKey),
                        _langDef.GetFunction(_langDef.funcEQ, new VariableDef(_langDef.GuidType, Information.ExtractPropertyPath <Message>(x => x.MessageType)), s.MessageType.__PrimaryKey)))
                                            .ToArray();
                Function subscriptionsCondition = _langDef.GetFunction(_langDef.funcOR, conditionsList);

                Function messagesLf = _langDef.GetFunction(
                    _langDef.funcAND,
                    subscriptionsCondition,
                    _langDef.GetFunction(_langDef.funcEQ, new VariableDef(_langDef.BoolType, Information.ExtractPropertyPath <Message>(x => x.IsSending)), false),
                    _langDef.GetFunction(_langDef.funcLEQ, new VariableDef(_langDef.DateTimeType, Information.ExtractPropertyPath <Message>(x => x.SendingTime)), DateTime.Now));

                LoadingCustomizationStruct lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(Message), Message.Views.MessageEditView);
                lcs.LimitFunction = messagesLf;
                lcs.ReturnTop     = MaxTasks - _sendingTasksCount;
                lcs.ColumnsSort   = new[]
                {
                    new ColumnsSortDef(Information.ExtractPropertyPath <Message>(x => x.Priority), SortOrder.Asc),
                    new ColumnsSortDef(Information.ExtractPropertyPath <Message>(x => x.SendingTime), SortOrder.Asc)
                };

                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();

                DataObject[] messages = _dataService.LoadObjects(lcs);

                stopwatch.Stop();
                long time = stopwatch.ElapsedMilliseconds;
                _statisticsService.NotifyAvgTimeSql(null, (int)time, "OptimizedSendingManager.ScanMessages() load messages.");

                int index = 0;
                while (index < messages.Length && TryEnqueue((Message)messages[index]))
                {
                    index++;
                }
            }
            catch (Exception exception)
            {
                _logger.LogError("Send message error", exception.ToString());
            }
        }