@checkstack/healthcheck-backend 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +212 -0
- package/package.json +14 -14
- package/src/automations.test.ts +255 -0
- package/src/automations.ts +340 -0
- package/src/hooks.ts +69 -4
- package/src/index.ts +37 -52
- package/src/queue-executor.test.ts +137 -0
- package/src/queue-executor.ts +130 -27
- package/src/router.test.ts +5 -0
- package/src/router.ts +12 -1
- package/src/service-assignments.test.ts +184 -0
- package/src/service.ts +65 -0
- package/tsconfig.json +3 -3
package/src/service.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
DEFAULT_NOTIFICATION_POLICY,
|
|
12
12
|
} from "@checkstack/healthcheck-common";
|
|
13
13
|
import type { ConfigService } from "@checkstack/backend-api";
|
|
14
|
+
import type { InferClient } from "@checkstack/common";
|
|
15
|
+
import type { CatalogApi } from "@checkstack/catalog-common";
|
|
14
16
|
import {
|
|
15
17
|
notificationDefaultsConfigV1,
|
|
16
18
|
NOTIFICATION_DEFAULTS_CONFIG_ID,
|
|
@@ -56,6 +58,10 @@ import {
|
|
|
56
58
|
// Drizzle type helper - uses SafeDatabase to prevent relational query API usage
|
|
57
59
|
type Db = SafeDatabase<typeof schema>;
|
|
58
60
|
|
|
61
|
+
// Catalog client type used to resolve human-readable system names for
|
|
62
|
+
// satellite assignment run-context. Optional on the service.
|
|
63
|
+
type CatalogClient = InferClient<typeof CatalogApi>;
|
|
64
|
+
|
|
59
65
|
interface SystemCheckStatus {
|
|
60
66
|
configurationId: string;
|
|
61
67
|
configurationName: string;
|
|
@@ -83,6 +89,12 @@ export class HealthCheckService {
|
|
|
83
89
|
* have to plumb it through.
|
|
84
90
|
*/
|
|
85
91
|
private configService?: ConfigService,
|
|
92
|
+
/**
|
|
93
|
+
* Optional — used to resolve human-readable system names when building
|
|
94
|
+
* satellite assignment run-context. When absent (e.g. GitOps-only /
|
|
95
|
+
* test constructions), `systemName` falls back to the `systemId`.
|
|
96
|
+
*/
|
|
97
|
+
private catalogClient?: CatalogClient,
|
|
86
98
|
) {}
|
|
87
99
|
|
|
88
100
|
/**
|
|
@@ -242,6 +254,35 @@ export class HealthCheckService {
|
|
|
242
254
|
});
|
|
243
255
|
}
|
|
244
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Flip the `enabled` flag on an existing `systemHealthChecks` row
|
|
259
|
+
* without touching any of the other configuration (thresholds,
|
|
260
|
+
* satellite assignment, notification policy). Returns `true` when a
|
|
261
|
+
* row was updated, `false` when the assignment doesn't exist.
|
|
262
|
+
*
|
|
263
|
+
* Carved out so the automation actions `enable_assignment` /
|
|
264
|
+
* `disable_assignment` don't have to round-trip through
|
|
265
|
+
* `associateSystem` (which would otherwise wipe operator-managed
|
|
266
|
+
* fields when invoked with a sparse partial).
|
|
267
|
+
*/
|
|
268
|
+
async setAssignmentEnabled(
|
|
269
|
+
systemId: string,
|
|
270
|
+
configurationId: string,
|
|
271
|
+
enabled: boolean,
|
|
272
|
+
): Promise<boolean> {
|
|
273
|
+
const result = await this.db
|
|
274
|
+
.update(systemHealthChecks)
|
|
275
|
+
.set({ enabled, updatedAt: new Date() })
|
|
276
|
+
.where(
|
|
277
|
+
and(
|
|
278
|
+
eq(systemHealthChecks.systemId, systemId),
|
|
279
|
+
eq(systemHealthChecks.configurationId, configurationId),
|
|
280
|
+
),
|
|
281
|
+
)
|
|
282
|
+
.returning({ systemId: systemHealthChecks.systemId });
|
|
283
|
+
return result.length > 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
245
286
|
async disassociateSystem(systemId: string, configurationId: string) {
|
|
246
287
|
await this.db
|
|
247
288
|
.delete(systemHealthChecks)
|
|
@@ -1197,6 +1238,27 @@ export class HealthCheckService {
|
|
|
1197
1238
|
|
|
1198
1239
|
if (matchingAssociations.length === 0) return [];
|
|
1199
1240
|
|
|
1241
|
+
// Resolve human-readable system names once per distinct systemId.
|
|
1242
|
+
// Falls back to the systemId when no catalog client is wired or the
|
|
1243
|
+
// lookup fails, mirroring the queue-executor's resolution behaviour.
|
|
1244
|
+
const systemNameCache = new Map<string, string>();
|
|
1245
|
+
const resolveSystemName = async (systemId: string): Promise<string> => {
|
|
1246
|
+
const cached = systemNameCache.get(systemId);
|
|
1247
|
+
if (cached !== undefined) return cached;
|
|
1248
|
+
|
|
1249
|
+
let systemName = systemId;
|
|
1250
|
+
if (this.catalogClient) {
|
|
1251
|
+
try {
|
|
1252
|
+
const system = await this.catalogClient.getSystem({ systemId });
|
|
1253
|
+
if (system) systemName = system.name;
|
|
1254
|
+
} catch {
|
|
1255
|
+
// Fall back to systemId if catalog lookup fails.
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
systemNameCache.set(systemId, systemName);
|
|
1259
|
+
return systemName;
|
|
1260
|
+
};
|
|
1261
|
+
|
|
1200
1262
|
// Get configurations for each matching association
|
|
1201
1263
|
const assignments = [];
|
|
1202
1264
|
for (const assoc of matchingAssociations) {
|
|
@@ -1214,6 +1276,9 @@ export class HealthCheckService {
|
|
|
1214
1276
|
config: config.config,
|
|
1215
1277
|
collectors: config.collectors ?? undefined,
|
|
1216
1278
|
intervalSeconds: config.intervalSeconds,
|
|
1279
|
+
// Curated run-context metadata exposed to satellite collectors.
|
|
1280
|
+
configName: config.name,
|
|
1281
|
+
systemName: await resolveSystemName(assoc.systemId),
|
|
1217
1282
|
});
|
|
1218
1283
|
}
|
|
1219
1284
|
|
package/tsconfig.json
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
"src"
|
|
5
5
|
],
|
|
6
6
|
"references": [
|
|
7
|
+
{
|
|
8
|
+
"path": "../automation-backend"
|
|
9
|
+
},
|
|
7
10
|
{
|
|
8
11
|
"path": "../backend-api"
|
|
9
12
|
},
|
|
@@ -43,9 +46,6 @@
|
|
|
43
46
|
{
|
|
44
47
|
"path": "../incident-common"
|
|
45
48
|
},
|
|
46
|
-
{
|
|
47
|
-
"path": "../integration-backend"
|
|
48
|
-
},
|
|
49
49
|
{
|
|
50
50
|
"path": "../maintenance-common"
|
|
51
51
|
},
|