class NotificationManager {

    @Transactional(propagation = Propagation.REQUIRED)
    public void notifyHighResourceConsumingRuns(
            final List<Pair<PipelineRun, Map<ELKUsageMetric, Double>>> pipelinesMetrics,
            final NotificationType notificationType) {
        if (CollectionUtils.isEmpty(pipelinesMetrics)) {
            LOGGER.debug("No pipelines are high loaded, notifications won't be sent!");
            return;
        }

        final NotificationSettings notificationSettings = notificationSettingsManager.load(notificationType);
        if (notificationSettings == null || !notificationSettings.isEnabled()) {
            LOGGER.info("No template configured for high consuming pipeline run notifications or it was disabled!");
            return;
        }

        final List<Pair<PipelineRun, Map<ELKUsageMetric, Double>>> filtered = pipelinesMetrics.stream()
                .filter(run -> shouldNotify(run.getLeft().getId(), notificationSettings))
                .collect(Collectors.toList());

        LOGGER.debug("High resource consuming notifications for pipelines: " +
                filtered.stream()
                        .map(p -> p.getLeft().getId().toString())
                        .collect(Collectors.joining(",")) + " will be sent!");

        final List<Long> ccUserIds = getCCUsers(notificationSettings);

        final Map<String, PipelineUser> pipelineOwners = getPipelinesOwners(filtered);

        final double memThreshold = preferenceManager.getPreference(SystemPreferences.SYSTEM_MEMORY_THRESHOLD_PERCENT);
        final double diskThreshold = preferenceManager.getPreference(SystemPreferences.SYSTEM_DISK_THRESHOLD_PERCENT);

        final List<NotificationMessage> messages = filtered.stream().map(pair -> {
            NotificationMessage message = new NotificationMessage();
            message.setTemplate(new NotificationTemplate(notificationSettings.getTemplateId()));
            message.setTemplateParameters(PipelineRunMapper.map(pair.getLeft(), null));
            message.getTemplateParameters().put("memoryThreshold", memThreshold);
            message.getTemplateParameters().put("memoryRate",
                    pair.getRight().getOrDefault(ELKUsageMetric.MEM, 0.0) * PERCENT);
            message.getTemplateParameters().put("diskThreshold", diskThreshold);
            message.getTemplateParameters().put("diskRate", pair.getRight()
                    .getOrDefault(ELKUsageMetric.FS, 0.0) * PERCENT);
            if (notificationSettings.isKeepInformedOwner()) {
                message.setToUserId(pipelineOwners.getOrDefault(pair.getLeft().getOwner(), new PipelineUser()).getId());
            }
            message.setCopyUserIds(ccUserIds);
            return message;
        }).collect(Collectors.toList());

        final List<Long> runIds = filtered.stream()
                .map(pm -> pm.getLeft().getId()).collect(Collectors.toList());
        monitoringNotificationDao.createMonitoringNotifications(messages);
        monitoringNotificationDao.updateNotificationTimestamp(runIds, notificationType);
    }

}