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>
This commit is contained in:
SID 2026-01-12 07:49:43 -08:00 committed by GitHub
parent 2b2941cd83
commit c7a8b7affd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 64 additions and 5 deletions

View File

@ -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");
});
};

View File

@ -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,6 +935,16 @@ class Monitor extends BeanModel {
// Just reset the retries
if (this.isUpsideDown() && bean.status === UP) {
retries = 0;
} 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;
@ -941,6 +952,16 @@ class Monitor extends BeanModel {
// Continue counting retries during DOWN
retries++;
}
} else {
// 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++;
}
}
}
bean.retries = retries;

View File

@ -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;

View File

@ -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",

View File

@ -1167,6 +1167,24 @@
</div>
</div>
<!-- Retry only on status code failure: JSON Query only -->
<div v-if="monitor.type === 'json-query' && monitor.maxretries > 0" class="my-3">
<div class="form-check">
<input
id="retry-only-on-status-code-failure"
v-model="monitor.retryOnlyOnStatusCodeFailure"
type="checkbox"
class="form-check-input"
/>
<label for="retry-only-on-status-code-failure" class="form-check-label">
{{ $t("Only retry if status code check fails") }}
</label>
</div>
<div class="form-text">
{{ $t("retryOnlyOnStatusCodeFailureDescription") }}
</div>
</div>
<!-- Timeout: HTTP / JSON query / Keyword / Ping / RabbitMQ / SNMP / Websocket Upgrade only -->
<div
v-if="
@ -2158,6 +2176,7 @@ const monitorDefaults = {
retryInterval: 60,
resendInterval: 0,
maxretries: 0,
retryOnlyOnStatusCodeFailure: false,
notificationIDList: {},
ignoreTls: false,
upsideDown: false,