From 7e2503c0dcf27e787e2e59511df276b4bf685819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Kr=C3=BDda?= Date: Sun, 30 Jan 2022 20:55:53 +0100 Subject: [PATCH] Added the option not to send notifications if the master monitor is pending, down or degraded. --- db/patch-dependent-monitors-table.sql | 3 +++ server/model/monitor.js | 31 ++++++++++++++++++++++----- server/routers/api-router.js | 9 ++++++-- server/server.js | 1 + src/languages/en.js | 3 +++ src/pages/Details.vue | 16 +++++++------- src/pages/EditMonitor.vue | 14 ++++++++++-- 7 files changed, 60 insertions(+), 17 deletions(-) diff --git a/db/patch-dependent-monitors-table.sql b/db/patch-dependent-monitors-table.sql index 3ba2aaff1..2b26648ed 100644 --- a/db/patch-dependent-monitors-table.sql +++ b/db/patch-dependent-monitors-table.sql @@ -1,6 +1,9 @@ -- You should not modify if this have pushed to Github, unless it does serious wrong with the db. BEGIN TRANSACTION; +ALTER TABLE monitor + ADD no_notification_if_master_down BOOLEAN default 0 NOT NULL; + CREATE TABLE dependent_monitors ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, diff --git a/server/model/monitor.js b/server/model/monitor.js index 8d99b472f..1d6cb7927 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -72,6 +72,7 @@ class Monitor extends BeanModel { keyword: this.keyword, ignoreTls: this.getIgnoreTls(), upsideDown: this.isUpsideDown(), + noNotificationIfMasterDown: this.getNoNotificationIfMasterDown(), maxredirects: this.maxredirects, accepted_statuscodes: this.getAcceptedStatuscodes(), dns_resolve_type: this.dns_resolve_type, @@ -108,6 +109,14 @@ class Monitor extends BeanModel { return Boolean(this.upsideDown); } + /** + * Parse to boolean + * @returns {boolean} + */ + getNoNotificationIfMasterDown() { + return Boolean(this.noNotificationIfMasterDown); + } + getAcceptedStatuscodes() { return JSON.parse(this.accepted_statuscodes_json); } @@ -148,7 +157,10 @@ class Monitor extends BeanModel { bean.duration = 0; } + let isDegraded = false; + try { + isDegraded = await Monitor.isDegraded(this.id); if (this.type === "http" || this.type === "keyword") { // Do not do any queries/high loading things before the "bean.ping" let startTime = dayjs().valueOf(); @@ -363,8 +375,8 @@ class Monitor extends BeanModel { retries = 0; - if (bean.status === UP && await Monitor.isDegraded(this.id)) { - bean.msg = "Monitor is degraded, because at least one dependent monitor is DOWN"; + if (bean.status === UP && isDegraded) { + bean.msg = "Monitor is degraded, because at least one master monitor is pending, down or degraded"; bean.status = DEGRADED; } @@ -381,6 +393,12 @@ class Monitor extends BeanModel { retries++; bean.status = PENDING; } + + // Do not change this text! + // Condition below and in api-router depends on it + if (isDegraded && bean.status === DOWN) { + bean.msg = "Monitor is down and degraded"; + } } let beatInterval = this.interval; @@ -393,7 +411,10 @@ class Monitor extends BeanModel { if (isImportant) { bean.important = true; - if (Monitor.isImportantForNotification(isFirstBeat, previousBeat?.status, bean.status)) { + if (this.noNotificationIfMasterDown && isDegraded || previousBeat.msg === "Monitor is down and degraded") { + debug(`[${this.name}] will not sendNotification because it is/was degraded`); + } + else if (Monitor.isImportantForNotification(isFirstBeat, previousBeat?.status, bean.status)) { debug(`[${this.name}] sendNotification`); await Monitor.sendNotification(isFirstBeat, this, bean); } @@ -801,7 +822,7 @@ class Monitor extends BeanModel { static async getPreviousHeartbeat(monitorID) { return await R.getRow(` - SELECT status, time FROM heartbeat + SELECT msg, status, time FROM heartbeat WHERE id = (select MAX(id) from heartbeat where monitor_id = ?) `, [ monitorID @@ -811,7 +832,7 @@ class Monitor extends BeanModel { static async isDegraded(monitorID) { const monitors = await R.getAll(` SELECT hb.id FROM heartbeat hb JOIN dependent_monitors dm on hb.monitor_id = dm.depends_on JOIN (SELECT MAX(id) AS id FROM heartbeat GROUP BY monitor_id) USING (id) - WHERE dm.monitor_id = ? AND hb.status = 0 + WHERE dm.monitor_id = ? AND (hb.status = 0 OR hb.status = 2 OR hb.status = 4) `, [ monitorID ]); diff --git a/server/routers/api-router.js b/server/routers/api-router.js index f31bbabc0..5485f47a5 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -51,7 +51,9 @@ router.get("/api/push/:pushToken", async (request, response) => { duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second"); } - if (status === UP && await Monitor.isDegraded(monitor.id)) { + const isDegraded = await Monitor.isDegraded(monitor.id) + + if (status === UP && isDegraded) { msg = "Monitor is degraded, because at least one dependent monitor is DOWN"; status = DEGRADED; } @@ -75,7 +77,10 @@ router.get("/api/push/:pushToken", async (request, response) => { ok: true, }); - if (Monitor.isImportantForNotification(isFirstBeat, previousStatus, status)) { + if (monitor.noNotificationIfMasterDown && isDegraded || previousHeartbeat.msg === "Monitor is down and degraded") { + debug(`[${monitor.name}] will not sendNotification because it is/was degraded`); + } + else if (Monitor.isImportantForNotification(isFirstBeat, previousStatus, status)) { await Monitor.sendNotification(isFirstBeat, monitor, bean); } diff --git a/server/server.js b/server/server.js index 6a80605d5..7b5b44db2 100644 --- a/server/server.js +++ b/server/server.js @@ -594,6 +594,7 @@ exports.entryPage = "dashboard"; bean.keyword = monitor.keyword; bean.ignoreTls = monitor.ignoreTls; bean.upsideDown = monitor.upsideDown; + bean.noNotificationIfMasterDown = monitor.noNotificationIfMasterDown; bean.maxredirects = monitor.maxredirects; bean.accepted_statuscodes_json = JSON.stringify(monitor.accepted_statuscodes); bean.dns_resolve_type = monitor.dns_resolve_type; diff --git a/src/languages/en.js b/src/languages/en.js index a885c6ce9..4c7685af9 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -6,8 +6,11 @@ export default { ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites", upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.", maxRedirectDescription: "Maximum number of redirects to follow. Set to 0 to disable redirects.", + sendNotificationTitle: "Do not send notification in case of master monitor failure", + sendNotificationDescription: "Do not send any notifications if this monitor is DOWN and at least one master monitor is also DOWN.", Degraded: "Degraded", "Dependent Monitors": "Dependent Monitors", + monitorDependsOn: "The status of this monitor depends on", "Pick Dependent Monitors...": "Pick Dependent Monitors...", dependentMonitorsDescription: "Select the monitor(s) on which this monitor depends. If the dependent monitor(s) fails, this monitor will be affected too.", acceptedStatusCodesDescription: "Select status codes which are considered as a successful response.", diff --git a/src/pages/Details.vue b/src/pages/Details.vue index 65a60209d..7bc29d4d4 100644 --- a/src/pages/Details.vue +++ b/src/pages/Details.vue @@ -103,6 +103,14 @@ +
+ +
+ +
+
-
- -
- -
- {{ $t("pauseMonitorMsg") }} diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index ed5646d93..9b22ae784 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -156,6 +156,16 @@ +
+ + +
+ {{ $t("sendNotificationDescription") }} +
+
+