From c7a8b7affdd408e96f3d4b545f9cc2ba015f1a49 Mon Sep 17 00:00:00 2001 From: SID <158349177+0xsid0703@users.noreply.github.com> Date: Mon, 12 Jan 2026 07:49:43 -0800 Subject: [PATCH] feat: Add option to retry only on status code failure for JSON Query monitors (#5693) (#6687) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- ...0-add-json-query-retry-only-status-code.js | 12 +++++++ server/model/monitor.js | 31 ++++++++++++++++--- server/server.js | 5 +++ src/lang/en.json | 2 ++ src/pages/EditMonitor.vue | 19 ++++++++++++ 5 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 db/knex_migrations/2026-01-15-0000-add-json-query-retry-only-status-code.js diff --git a/db/knex_migrations/2026-01-15-0000-add-json-query-retry-only-status-code.js b/db/knex_migrations/2026-01-15-0000-add-json-query-retry-only-status-code.js new file mode 100644 index 000000000..dd5f0955a --- /dev/null +++ b/db/knex_migrations/2026-01-15-0000-add-json-query-retry-only-status-code.js @@ -0,0 +1,12 @@ +exports.up = function (knex) { + // Add new column to table monitor for json-query retry behavior + return knex.schema.alterTable("monitor", function (table) { + table.boolean("retry_only_on_status_code_failure").defaultTo(false).notNullable(); + }); +}; + +exports.down = function (knex) { + return knex.schema.alterTable("monitor", function (table) { + table.dropColumn("retry_only_on_status_code_failure"); + }); +}; diff --git a/server/model/monitor.js b/server/model/monitor.js index f05ddd744..600878936 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -144,6 +144,7 @@ class Monitor extends BeanModel { timeout: this.timeout, interval: this.interval, retryInterval: this.retryInterval, + retryOnlyOnStatusCodeFailure: Boolean(this.retry_only_on_status_code_failure), resendInterval: this.resendInterval, keyword: this.keyword, invertKeyword: this.isInvertKeyword(), @@ -934,12 +935,32 @@ class Monitor extends BeanModel { // Just reset the retries if (this.isUpsideDown() && bean.status === UP) { retries = 0; - } else if (this.maxretries > 0 && retries < this.maxretries) { - retries++; - bean.status = PENDING; + } else if (this.type === "json-query" && this.retry_only_on_status_code_failure) { + // For json-query monitors with retry_only_on_status_code_failure enabled, + // only retry if the error is NOT from JSON query evaluation + // JSON query errors have the message "JSON query does not pass..." + const isJsonQueryError = + typeof error.message === "string" && error.message.includes("JSON query does not pass"); + + if (isJsonQueryError) { + // Don't retry on JSON query failures, mark as DOWN immediately + retries = 0; + } else if (this.maxretries > 0 && retries < this.maxretries) { + retries++; + bean.status = PENDING; + } else { + // Continue counting retries during DOWN + retries++; + } } else { - // Continue counting retries during DOWN - retries++; + // General retry logic for all other monitor types + if (this.maxretries > 0 && retries < this.maxretries) { + retries++; + bean.status = PENDING; + } else { + // Continue counting retries during DOWN + retries++; + } } } diff --git a/server/server.js b/server/server.js index b683b7114..c6168b897 100644 --- a/server/server.js +++ b/server/server.js @@ -753,6 +753,10 @@ let needSetup = false; } bean.import(monitor); + // Map camelCase frontend property to snake_case database column + if (monitor.retryOnlyOnStatusCodeFailure !== undefined) { + bean.retry_only_on_status_code_failure = monitor.retryOnlyOnStatusCodeFailure; + } bean.user_id = socket.userID; bean.validate(); @@ -905,6 +909,7 @@ let needSetup = false; bean.snmpVersion = monitor.snmpVersion; bean.snmpOid = monitor.snmpOid; bean.jsonPathOperator = monitor.jsonPathOperator; + bean.retry_only_on_status_code_failure = Boolean(monitor.retryOnlyOnStatusCodeFailure); bean.timeout = monitor.timeout; bean.rabbitmqNodes = JSON.stringify(monitor.rabbitmqNodes); bean.rabbitmqUsername = monitor.rabbitmqUsername; diff --git a/src/lang/en.json b/src/lang/en.json index 72f38f9d2..d7f7fb7b5 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -86,6 +86,8 @@ "resendEveryXTimes": "Resend every {0} times", "resendDisabled": "Resend disabled", "retriesDescription": "Maximum retries before the service is marked as down and a notification is sent", + "Only retry if status code check fails": "Only retry if status code check fails", + "retryOnlyOnStatusCodeFailureDescription": "If enabled, retries will only occur when the HTTP status code check fails (e.g., server is down). If the status code check passes but the JSON query fails, the monitor will be marked as down immediately without retries.", "ignoredTLSError": "TLS/SSL errors have been ignored", "ignoreTLSError": "Ignore TLS/SSL errors for HTTPS websites", "ignoreTLSErrorGeneral": "Ignore TLS/SSL error for connection", diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 0a08c9a6f..3dad58dc8 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -1167,6 +1167,24 @@ + +
+
+ + +
+
+ {{ $t("retryOnlyOnStatusCodeFailureDescription") }} +
+
+