diff --git a/client/src/SettingsWizard.js b/client/src/SettingsWizard.js
index b5f7484..060a46c 100644
--- a/client/src/SettingsWizard.js
+++ b/client/src/SettingsWizard.js
@@ -35,6 +35,7 @@ function SettingsWizard() {
items_per_page: 20,
refresh_interval: 5000,
incident_failure_threshold: 10,
+ slow_alert_consecutive: 3,
});
const [testResult, setTestResult] = useState(null);
@@ -529,6 +530,18 @@ function SettingsWizard() {
Number of consecutive failures before triggering an alert (default: 3)
+
+
+ setSettings({ ...settings, slow_alert_consecutive: parseInt(e.target.value) })}
+ min="1"
+ max="20"
+ />
+ Consecutive slow checks required before alerting — 1 = any spike, 3 = default, 5+ = only sustained slowness
+
+
diff --git a/server/index.js b/server/index.js
index c2b3652..6fd140a 100644
--- a/server/index.js
+++ b/server/index.js
@@ -147,6 +147,7 @@ function buildSettingsFromDb(dbSettings = {}) {
ntfy_url: dbSettings.ntfy_url || process.env.NTFY_URL || 'https://ntfy.sh',
ntfy_topic: dbSettings.ntfy_topic || process.env.NTFY_TOPIC || '',
incident_failure_threshold: parseInt(dbSettings.incident_failure_threshold || process.env.INCIDENT_FAILURE_THRESHOLD) || 10,
+ slow_alert_consecutive: parseInt(dbSettings.slow_alert_consecutive || process.env.SLOW_ALERT_CONSECUTIVE) || 3,
webhook_template: dbSettings.webhook_template || process.env.WEBHOOK_TEMPLATE || '',
};
}
@@ -773,6 +774,7 @@ app.post('/api/settings', (req, res) => {
ntfy_url: { env: 'NTFY_URL', coerce: v => v || 'https://ntfy.sh' },
ntfy_topic: { env: 'NTFY_TOPIC', coerce: v => v || '' },
incident_failure_threshold: { env: 'INCIDENT_FAILURE_THRESHOLD', coerce: v => String(v || 10) },
+ slow_alert_consecutive: { env: 'SLOW_ALERT_CONSECUTIVE', coerce: v => String(v || 3) },
};
// Collect only the fields present in this request
diff --git a/server/scheduler.js b/server/scheduler.js
index 861191b..a55e63c 100644
--- a/server/scheduler.js
+++ b/server/scheduler.js
@@ -181,8 +181,9 @@ class Scheduler {
if (result.response_time > effectiveThreshold) {
const consecutive = (this.slowConsecutiveCount.get(resource.id) || 0) + 1;
this.slowConsecutiveCount.set(resource.id, consecutive);
- // Require 3 consecutive slow checks before alerting (avoids single-spike false positives)
- if (consecutive >= 3) {
+ const slowAlertConsecutiveSetting = db.prepare(`SELECT value FROM settings WHERE key = 'slow_alert_consecutive'`).get();
+ const slowAlertConsecutive = parseInt(slowAlertConsecutiveSetting?.value) || 3;
+ if (consecutive >= slowAlertConsecutive) {
const lastSlowAlert = this.slowAlertCooldown.get(resource.id) || 0;
if (now - lastSlowAlert > 60 * 60 * 1000) {
this.slowAlertCooldown.set(resource.id, now);