/// <summary>
        /// Отправка уведомлений из указанной StorageDb
        /// </summary>
        protected void ProcessAccount(ForEachAccountData data, Guid?componentId = null)
        {
            var notificationRepository = data.AccountDbContext.GetNotificationRepository();

            var notificationsQuery = notificationRepository.GetForSend(NotificationType);

            if (componentId.HasValue)
            {
                notificationsQuery = notificationsQuery.Where(t => t.Event.OwnerId == componentId.Value);
            }

            var notifications = notificationsQuery.OrderBy(t => t.CreationDate).Take(MaxNotificationCount).ToList();

            if (notifications.Count > 0)
            {
                data.Logger.Debug("Найдено уведомлений: " + notifications.Count);
                foreach (var notification in notifications)
                {
                    data.CancellationToken.ThrowIfCancellationRequested();

                    try
                    {
                        data.Logger.Debug("Обработка уведомления " + notification.Id);

                        Send(data.Logger,
                             notification,
                             data.AccountDbContext,
                             data.Account.SystemName, data.Account.Id);

                        notification.Status   = NotificationStatus.Sended;
                        notification.SendDate = DateTime.Now;
                        data.AccountDbContext.SaveChanges();

                        data.Logger.Info("Уведомление " + notification.Id + " отправлено на " + notification.Address);
                        Interlocked.Increment(ref CreatedNotificationsCount);
                    }
                    catch (NotificationNonImportantException exception)
                    {
                        // ошибка при отправке, которая не считается важной
                        data.Logger.Info(exception);

                        // обновим статус
                        notification.SendError = (exception.InnerException ?? exception).ToString();
                        notification.Status    = NotificationStatus.Error;
                        notification.SendDate  = DateTime.Now;
                        data.AccountDbContext.SaveChanges();

                        // TODO отправить ошибку в компонент аккаунта, чтобы её увидел админ аккаунта (а не админ Зидиума)
                    }
                    catch (Exception exception)
                    {
                        // залогируем ошибку
                        DbProcessor.SetException(exception);
                        data.Logger.Error(exception);

                        // обновим статус
                        notification.SendError = exception.ToString();
                        notification.Status    = NotificationStatus.Error;
                        notification.SendDate  = DateTime.Now;
                        data.AccountDbContext.SaveChanges();
                    }
                }
            }
            else
            {
                data.Logger.Trace("Новых уведомлений нет");
            }
        }
        protected override Core.Api.SendUnitTestResultRequestData GetResult(
            Guid accountId,
            AccountDbContext accountDbContext,
            UnitTest unitTest,
            ILogger logger,
            CancellationToken token)
        {
            if (unitTest == null)
            {
                throw new ArgumentNullException("unitTest");
            }
            if (unitTest.DomainNamePaymentPeriodRule == null)
            {
                // Правило ещё не создалось, бывает
                return(new Core.Api.SendUnitTestResultRequestData()
                {
                    Result = Core.Api.UnitTestResult.Unknown
                });
            }
            var rule = unitTest.DomainNamePaymentPeriodRule;

            if (string.IsNullOrWhiteSpace(rule.Domain))
            {
                throw new UserFriendlyException("Не указан домен для проверки");
            }

            var resultInfo = GetPaymentDate(rule.Domain);

            // Сервис недоступен
            if (resultInfo.Code == DomainNamePaymentPeriodErrorCode.Unavailable)
            {
                // Отмена выполнения
                logger.Warn(resultInfo.ErrorMessage);

                throw new OperationCanceledException();
            }

            if (resultInfo.Code == DomainNamePaymentPeriodErrorCode.UnknownError)
            {
                var logEvent = new LogEventInfo()
                {
                    Level   = NLog.LogLevel.Warn,
                    Message = "Произошла неизвестная ошибка"
                };
                logEvent.Properties["Html"] = resultInfo.Html;
                logger.Log(logEvent);

                DbProcessor.SetException(new UserFriendlyException(resultInfo.ErrorMessage));
            }

            if (resultInfo.Date == null)
            {
                rule.LastRunErrorCode = resultInfo.Code;
                return(new Core.Api.SendUnitTestResultRequestData()
                {
                    Result = Core.Api.UnitTestResult.Alarm,
                    Message = resultInfo.ErrorMessage
                });
            }

            var days = (int)((resultInfo.Date.Value - DateTime.Now.Date).TotalDays);

            rule.LastRunErrorCode = DomainNamePaymentPeriodErrorCode.Success;
            var result = new Core.Api.SendUnitTestResultRequestData()
            {
                Message = string.Format(
                    "Осталось {0} дней до окончания срока оплаты. Домен оплачен до {1}",
                    days,
                    resultInfo.Date.Value.ToString("dd.MM.yyyy"))
            };

            if (days <= rule.AlarmDaysCount)
            {
                result.Result = Core.Api.UnitTestResult.Alarm;
            }
            else if (days <= rule.WarningDaysCount)
            {
                result.Result = Core.Api.UnitTestResult.Warning;
            }
            else
            {
                result.Result = Core.Api.UnitTestResult.Success;
            }
            return(result);
        }