feat(health-check): introduce health probe gap configuration and enhance health check logic
Build and Push CFDM Docker Image / build-and-push (push) Successful in 2m0s
Build and Push CFDM Docker Image / create-release (push) Skipped
Build and Push CFDM Docker Image / update-wiki (push) Successful in 6s

Added `healthProbeGapMs` configuration to control the minimum pause between probes to different physical targets. Updated health check service to utilize this configuration, ensuring efficient probing without overwhelming the targets. Enhanced the `runAllChecks` function to group probes by physical IP and implement the new gap logic. Updated related tests to validate the new functionality.
This commit is contained in:
Denozordec
2026-07-20 03:57:37 +07:00
parent a58d91ff5e
commit 9783974949
8 changed files with 270 additions and 66 deletions
+44 -1
View File
File diff suppressed because one or more lines are too long
+41 -1
View File
@@ -194,6 +194,9 @@ var appSettings = sqliteTable("app_settings", {
mode: "boolean"
}).notNull().default(false),
vps_tracker_last_sync_at: text("vps_tracker_last_sync_at"),
show_quick_actions: integer("show_quick_actions", {
mode: "boolean"
}).notNull().default(true),
created_at: text("created_at").notNull().default(sql`datetime('now')`),
updated_at: text("updated_at").notNull().default(sql`datetime('now')`)
});
@@ -345,6 +348,14 @@ var DEFAULT_APP_SWITCHER = {
url: "http://192.168.100.67:6363",
icon: "cloud",
shortcut: "\u23182"
},
{
id: "evobgp",
name: "EvoBGP",
subtitle: "BGP \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044F",
url: "http://192.168.100.67:3000",
icon: "globe",
shortcut: "\u23183"
}
]
};
@@ -365,7 +376,8 @@ function toDto(row) {
row.vps_tracker_integration_token?.trim()
),
vpsTrackerSyncEnabled: Boolean(row.vps_tracker_sync_enabled),
vpsTrackerLastSyncAt: row.vps_tracker_last_sync_at
vpsTrackerLastSyncAt: row.vps_tracker_last_sync_at,
showQuickActions: row.show_quick_actions == null ? true : Boolean(row.show_quick_actions)
};
}
function getAppSettings(db) {
@@ -397,6 +409,7 @@ function updateAppSettings(db, patch) {
vps_tracker_url: patch.vpsTrackerUrl !== void 0 ? patch.vpsTrackerUrl : current.vps_tracker_url,
vps_tracker_integration_token: patch.vpsTrackerIntegrationToken !== void 0 && patch.vpsTrackerIntegrationToken.trim() !== "" ? patch.vpsTrackerIntegrationToken : current.vps_tracker_integration_token,
vps_tracker_sync_enabled: patch.vpsTrackerSyncEnabled !== void 0 ? patch.vpsTrackerSyncEnabled : current.vps_tracker_sync_enabled,
show_quick_actions: patch.showQuickActions !== void 0 ? patch.showQuickActions : current.show_quick_actions,
updated_at: (/* @__PURE__ */ new Date()).toISOString()
}).where(eq(appSettings.id, SETTINGS_ID)).run();
return getAppSettings(db);
@@ -492,6 +505,7 @@ __export(repos_exports, {
listUngroupedServices: () => listUngroupedServices,
markDnsPendingDelete: () => markDnsPendingDelete,
mergeHealthAggregates: () => mergeHealthAggregates,
pruneStaleIpHealthStatus: () => pruneStaleIpHealthStatus,
reorderServices: () => reorderServices,
replaceBindingIps: () => replaceBindingIps,
replaceBindingIpsWithMeta: () => replaceBindingIpsWithMeta,
@@ -1443,6 +1457,32 @@ function deleteIpHealthStatusForIp(db, scope, refId, ip) {
)
).run();
}
function pruneStaleIpHealthStatus(db, activeTargets) {
const byRef = /* @__PURE__ */ new Map();
for (const t of activeTargets) {
const key = `${t.scope}:${t.ref_id}`;
let ips = byRef.get(key);
if (!ips) {
ips = /* @__PURE__ */ new Set();
byRef.set(key, ips);
}
ips.add(t.ip);
}
let deleted = 0;
for (const [key, ips] of byRef) {
const sep = key.indexOf(":");
const scope = key.slice(0, sep);
const refId = Number(key.slice(sep + 1));
if (!Number.isFinite(refId)) continue;
for (const row of listIpHealthStatus(db, scope, refId)) {
if (!ips.has(row.ip)) {
deleteIpHealthStatusForIp(db, scope, refId, row.ip);
deleted += 1;
}
}
}
return deleted;
}
function listHealthCheckTargets(db) {
const fqdnExpr = sql2`CASE WHEN sb.hostname = '@' OR sb.hostname IS NULL THEN d.zone_name ELSE sb.hostname || '.' || d.zone_name END`;
const bindingTargets = db.all(sql2`
+32
View File
@@ -1687,6 +1687,38 @@ export function deleteIpHealthStatusForIp(
.run();
}
/** Drop health rows whose IP is no longer a live probe target for that scope/ref. */
export function pruneStaleIpHealthStatus(
db: Db,
activeTargets: Array<{ scope: HealthCheckScope; ref_id: number; ip: string }>,
): number {
const byRef = new Map<string, Set<string>>();
for (const t of activeTargets) {
const key = `${t.scope}:${t.ref_id}`;
let ips = byRef.get(key);
if (!ips) {
ips = new Set();
byRef.set(key, ips);
}
ips.add(t.ip);
}
let deleted = 0;
for (const [key, ips] of byRef) {
const sep = key.indexOf(":");
const scope = key.slice(0, sep) as HealthCheckScope;
const refId = Number(key.slice(sep + 1));
if (!Number.isFinite(refId)) continue;
for (const row of listIpHealthStatus(db, scope, refId)) {
if (!ips.has(row.ip)) {
deleteIpHealthStatusForIp(db, scope, refId, row.ip);
deleted += 1;
}
}
}
return deleted;
}
// --- Health Check Targets ---
export function listHealthCheckTargets(db: Db): HealthCheckTarget[] {