@checkstack/healthcheck-backend 0.16.5 → 0.17.1
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 +35 -0
- package/drizzle/0011_fluffy_sphinx.sql +16 -0
- package/drizzle/meta/0011_snapshot.json +441 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +4 -4
- package/src/queue-executor.ts +11 -6
- package/src/schema.ts +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @checkstack/healthcheck-backend
|
|
2
2
|
|
|
3
|
+
## 0.17.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- c4e7560: Fix data integrity, cache invalidation, and mobile UI issues
|
|
8
|
+
|
|
9
|
+
- **Centralized mutation cache invalidation**: Every mutation now automatically invalidates its plugin's query cache on success via the shared `createProcedureHook` in `orpc-query.tsx`. This ensures all views stay in sync without requiring individual components to remember manual `invalidateQueries` calls.
|
|
10
|
+
- **Fixed oRPC query key matching**: Query keys use nested arrays (`[["pluginId"]]`) to correctly match oRPC's `[pathArray, options]` key structure. Fixed the broken flat-string pattern in `SystemBadgeDataProvider`.
|
|
11
|
+
- **Fixed hourly aggregation duplication**: Added `NULLS NOT DISTINCT` to the `health_check_aggregates` unique constraint so local runs (`source_id = NULL`) correctly conflict-match instead of creating duplicate hourly buckets. Includes a migration to clean up existing duplicates.
|
|
12
|
+
- **Fixed modal scrolling on mobile**: Added `max-height` + `overflow-y-auto` to `ConfirmationModal`, and refactored `Dialog` from translate-centering to flex-centering with `dvh` units for reliable mobile scroll containment.
|
|
13
|
+
- @checkstack/catalog-common@1.5.1
|
|
14
|
+
- @checkstack/incident-common@0.4.8
|
|
15
|
+
- @checkstack/maintenance-common@0.4.10
|
|
16
|
+
- @checkstack/satellite-backend@0.2.15
|
|
17
|
+
- @checkstack/catalog-backend@0.6.1
|
|
18
|
+
|
|
19
|
+
## 0.17.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- 298bf42: ### Notification System Optimizations
|
|
24
|
+
|
|
25
|
+
**System context in notifications**: All notification senders (healthcheck, incident, maintenance, dependency) now include the affected system name in the notification title and body. Users can immediately identify which system is affected without clicking through to the detail page.
|
|
26
|
+
|
|
27
|
+
**Upstream notification deduplication**: When an upstream dependency goes down affecting multiple downstream systems, the dependency notification sidecar now sends **one personalized notification per user** instead of one notification per affected system. Each user's notification lists only the systems they are subscribed to, with a link to the upstream root cause system. This prevents notification floods for users subscribed to groups containing many dependent systems.
|
|
28
|
+
|
|
29
|
+
**New catalog endpoint**: Added `getSystemGroupIds` S2S RPC endpoint on the catalog to resolve which catalog groups contain a given system, used by the dependency plugin for efficient subscriber resolution during batched notification dispatch.
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- Updated dependencies [298bf42]
|
|
34
|
+
- @checkstack/catalog-common@1.5.0
|
|
35
|
+
- @checkstack/catalog-backend@0.6.0
|
|
36
|
+
- @checkstack/satellite-backend@0.2.14
|
|
37
|
+
|
|
3
38
|
## 0.16.5
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
DROP INDEX "health_check_aggregates_bucket_unique";--> statement-breakpoint
|
|
2
|
+
|
|
3
|
+
-- Clean up duplicate local (source_id IS NULL) hourly buckets that were
|
|
4
|
+
-- created due to the missing NULLS NOT DISTINCT clause. Keep the row with
|
|
5
|
+
-- the highest id (most recent insert) for each bucket group.
|
|
6
|
+
DELETE FROM "health_check_aggregates" a
|
|
7
|
+
USING "health_check_aggregates" b
|
|
8
|
+
WHERE a.source_id IS NULL
|
|
9
|
+
AND b.source_id IS NULL
|
|
10
|
+
AND a.configuration_id = b.configuration_id
|
|
11
|
+
AND a.system_id = b.system_id
|
|
12
|
+
AND a.bucket_start = b.bucket_start
|
|
13
|
+
AND a.bucket_size = b.bucket_size
|
|
14
|
+
AND a.id < b.id;--> statement-breakpoint
|
|
15
|
+
|
|
16
|
+
ALTER TABLE "health_check_aggregates" ADD CONSTRAINT "health_check_aggregates_bucket_unique" UNIQUE NULLS NOT DISTINCT("configuration_id","system_id","bucket_start","bucket_size","source_id");
|
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "446eaec3-7894-4425-b7db-00c7761ca83f",
|
|
3
|
+
"prevId": "743f0b98-66a5-462e-8c35-4b2eb3093010",
|
|
4
|
+
"version": "7",
|
|
5
|
+
"dialect": "postgresql",
|
|
6
|
+
"tables": {
|
|
7
|
+
"public.health_check_aggregates": {
|
|
8
|
+
"name": "health_check_aggregates",
|
|
9
|
+
"schema": "",
|
|
10
|
+
"columns": {
|
|
11
|
+
"id": {
|
|
12
|
+
"name": "id",
|
|
13
|
+
"type": "uuid",
|
|
14
|
+
"primaryKey": true,
|
|
15
|
+
"notNull": true,
|
|
16
|
+
"default": "gen_random_uuid()"
|
|
17
|
+
},
|
|
18
|
+
"configuration_id": {
|
|
19
|
+
"name": "configuration_id",
|
|
20
|
+
"type": "uuid",
|
|
21
|
+
"primaryKey": false,
|
|
22
|
+
"notNull": true
|
|
23
|
+
},
|
|
24
|
+
"system_id": {
|
|
25
|
+
"name": "system_id",
|
|
26
|
+
"type": "text",
|
|
27
|
+
"primaryKey": false,
|
|
28
|
+
"notNull": true
|
|
29
|
+
},
|
|
30
|
+
"bucket_start": {
|
|
31
|
+
"name": "bucket_start",
|
|
32
|
+
"type": "timestamp",
|
|
33
|
+
"primaryKey": false,
|
|
34
|
+
"notNull": true
|
|
35
|
+
},
|
|
36
|
+
"bucket_size": {
|
|
37
|
+
"name": "bucket_size",
|
|
38
|
+
"type": "bucket_size",
|
|
39
|
+
"typeSchema": "public",
|
|
40
|
+
"primaryKey": false,
|
|
41
|
+
"notNull": true
|
|
42
|
+
},
|
|
43
|
+
"run_count": {
|
|
44
|
+
"name": "run_count",
|
|
45
|
+
"type": "integer",
|
|
46
|
+
"primaryKey": false,
|
|
47
|
+
"notNull": true
|
|
48
|
+
},
|
|
49
|
+
"healthy_count": {
|
|
50
|
+
"name": "healthy_count",
|
|
51
|
+
"type": "integer",
|
|
52
|
+
"primaryKey": false,
|
|
53
|
+
"notNull": true
|
|
54
|
+
},
|
|
55
|
+
"degraded_count": {
|
|
56
|
+
"name": "degraded_count",
|
|
57
|
+
"type": "integer",
|
|
58
|
+
"primaryKey": false,
|
|
59
|
+
"notNull": true
|
|
60
|
+
},
|
|
61
|
+
"unhealthy_count": {
|
|
62
|
+
"name": "unhealthy_count",
|
|
63
|
+
"type": "integer",
|
|
64
|
+
"primaryKey": false,
|
|
65
|
+
"notNull": true
|
|
66
|
+
},
|
|
67
|
+
"latency_sum_ms": {
|
|
68
|
+
"name": "latency_sum_ms",
|
|
69
|
+
"type": "integer",
|
|
70
|
+
"primaryKey": false,
|
|
71
|
+
"notNull": false
|
|
72
|
+
},
|
|
73
|
+
"avg_latency_ms": {
|
|
74
|
+
"name": "avg_latency_ms",
|
|
75
|
+
"type": "integer",
|
|
76
|
+
"primaryKey": false,
|
|
77
|
+
"notNull": false
|
|
78
|
+
},
|
|
79
|
+
"min_latency_ms": {
|
|
80
|
+
"name": "min_latency_ms",
|
|
81
|
+
"type": "integer",
|
|
82
|
+
"primaryKey": false,
|
|
83
|
+
"notNull": false
|
|
84
|
+
},
|
|
85
|
+
"max_latency_ms": {
|
|
86
|
+
"name": "max_latency_ms",
|
|
87
|
+
"type": "integer",
|
|
88
|
+
"primaryKey": false,
|
|
89
|
+
"notNull": false
|
|
90
|
+
},
|
|
91
|
+
"p95_latency_ms": {
|
|
92
|
+
"name": "p95_latency_ms",
|
|
93
|
+
"type": "integer",
|
|
94
|
+
"primaryKey": false,
|
|
95
|
+
"notNull": false
|
|
96
|
+
},
|
|
97
|
+
"aggregated_result": {
|
|
98
|
+
"name": "aggregated_result",
|
|
99
|
+
"type": "jsonb",
|
|
100
|
+
"primaryKey": false,
|
|
101
|
+
"notNull": false
|
|
102
|
+
},
|
|
103
|
+
"tdigest_state": {
|
|
104
|
+
"name": "tdigest_state",
|
|
105
|
+
"type": "jsonb",
|
|
106
|
+
"primaryKey": false,
|
|
107
|
+
"notNull": false
|
|
108
|
+
},
|
|
109
|
+
"source_id": {
|
|
110
|
+
"name": "source_id",
|
|
111
|
+
"type": "text",
|
|
112
|
+
"primaryKey": false,
|
|
113
|
+
"notNull": false
|
|
114
|
+
},
|
|
115
|
+
"source_label": {
|
|
116
|
+
"name": "source_label",
|
|
117
|
+
"type": "text",
|
|
118
|
+
"primaryKey": false,
|
|
119
|
+
"notNull": false
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"indexes": {},
|
|
123
|
+
"foreignKeys": {
|
|
124
|
+
"health_check_aggregates_configuration_id_health_check_configurations_id_fk": {
|
|
125
|
+
"name": "health_check_aggregates_configuration_id_health_check_configurations_id_fk",
|
|
126
|
+
"tableFrom": "health_check_aggregates",
|
|
127
|
+
"tableTo": "health_check_configurations",
|
|
128
|
+
"columnsFrom": [
|
|
129
|
+
"configuration_id"
|
|
130
|
+
],
|
|
131
|
+
"columnsTo": [
|
|
132
|
+
"id"
|
|
133
|
+
],
|
|
134
|
+
"onDelete": "cascade",
|
|
135
|
+
"onUpdate": "no action"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"compositePrimaryKeys": {},
|
|
139
|
+
"uniqueConstraints": {
|
|
140
|
+
"health_check_aggregates_bucket_unique": {
|
|
141
|
+
"name": "health_check_aggregates_bucket_unique",
|
|
142
|
+
"nullsNotDistinct": true,
|
|
143
|
+
"columns": [
|
|
144
|
+
"configuration_id",
|
|
145
|
+
"system_id",
|
|
146
|
+
"bucket_start",
|
|
147
|
+
"bucket_size",
|
|
148
|
+
"source_id"
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"policies": {},
|
|
153
|
+
"checkConstraints": {},
|
|
154
|
+
"isRLSEnabled": false
|
|
155
|
+
},
|
|
156
|
+
"public.health_check_configurations": {
|
|
157
|
+
"name": "health_check_configurations",
|
|
158
|
+
"schema": "",
|
|
159
|
+
"columns": {
|
|
160
|
+
"id": {
|
|
161
|
+
"name": "id",
|
|
162
|
+
"type": "uuid",
|
|
163
|
+
"primaryKey": true,
|
|
164
|
+
"notNull": true,
|
|
165
|
+
"default": "gen_random_uuid()"
|
|
166
|
+
},
|
|
167
|
+
"name": {
|
|
168
|
+
"name": "name",
|
|
169
|
+
"type": "text",
|
|
170
|
+
"primaryKey": false,
|
|
171
|
+
"notNull": true
|
|
172
|
+
},
|
|
173
|
+
"strategy_id": {
|
|
174
|
+
"name": "strategy_id",
|
|
175
|
+
"type": "text",
|
|
176
|
+
"primaryKey": false,
|
|
177
|
+
"notNull": true
|
|
178
|
+
},
|
|
179
|
+
"config": {
|
|
180
|
+
"name": "config",
|
|
181
|
+
"type": "jsonb",
|
|
182
|
+
"primaryKey": false,
|
|
183
|
+
"notNull": true
|
|
184
|
+
},
|
|
185
|
+
"collectors": {
|
|
186
|
+
"name": "collectors",
|
|
187
|
+
"type": "jsonb",
|
|
188
|
+
"primaryKey": false,
|
|
189
|
+
"notNull": false
|
|
190
|
+
},
|
|
191
|
+
"interval_seconds": {
|
|
192
|
+
"name": "interval_seconds",
|
|
193
|
+
"type": "integer",
|
|
194
|
+
"primaryKey": false,
|
|
195
|
+
"notNull": true
|
|
196
|
+
},
|
|
197
|
+
"is_template": {
|
|
198
|
+
"name": "is_template",
|
|
199
|
+
"type": "boolean",
|
|
200
|
+
"primaryKey": false,
|
|
201
|
+
"notNull": false,
|
|
202
|
+
"default": false
|
|
203
|
+
},
|
|
204
|
+
"paused": {
|
|
205
|
+
"name": "paused",
|
|
206
|
+
"type": "boolean",
|
|
207
|
+
"primaryKey": false,
|
|
208
|
+
"notNull": true,
|
|
209
|
+
"default": false
|
|
210
|
+
},
|
|
211
|
+
"created_at": {
|
|
212
|
+
"name": "created_at",
|
|
213
|
+
"type": "timestamp",
|
|
214
|
+
"primaryKey": false,
|
|
215
|
+
"notNull": true,
|
|
216
|
+
"default": "now()"
|
|
217
|
+
},
|
|
218
|
+
"updated_at": {
|
|
219
|
+
"name": "updated_at",
|
|
220
|
+
"type": "timestamp",
|
|
221
|
+
"primaryKey": false,
|
|
222
|
+
"notNull": true,
|
|
223
|
+
"default": "now()"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
"indexes": {},
|
|
227
|
+
"foreignKeys": {},
|
|
228
|
+
"compositePrimaryKeys": {},
|
|
229
|
+
"uniqueConstraints": {},
|
|
230
|
+
"policies": {},
|
|
231
|
+
"checkConstraints": {},
|
|
232
|
+
"isRLSEnabled": false
|
|
233
|
+
},
|
|
234
|
+
"public.health_check_runs": {
|
|
235
|
+
"name": "health_check_runs",
|
|
236
|
+
"schema": "",
|
|
237
|
+
"columns": {
|
|
238
|
+
"id": {
|
|
239
|
+
"name": "id",
|
|
240
|
+
"type": "uuid",
|
|
241
|
+
"primaryKey": true,
|
|
242
|
+
"notNull": true,
|
|
243
|
+
"default": "gen_random_uuid()"
|
|
244
|
+
},
|
|
245
|
+
"configuration_id": {
|
|
246
|
+
"name": "configuration_id",
|
|
247
|
+
"type": "uuid",
|
|
248
|
+
"primaryKey": false,
|
|
249
|
+
"notNull": true
|
|
250
|
+
},
|
|
251
|
+
"system_id": {
|
|
252
|
+
"name": "system_id",
|
|
253
|
+
"type": "text",
|
|
254
|
+
"primaryKey": false,
|
|
255
|
+
"notNull": true
|
|
256
|
+
},
|
|
257
|
+
"status": {
|
|
258
|
+
"name": "status",
|
|
259
|
+
"type": "health_check_status",
|
|
260
|
+
"typeSchema": "public",
|
|
261
|
+
"primaryKey": false,
|
|
262
|
+
"notNull": true
|
|
263
|
+
},
|
|
264
|
+
"latency_ms": {
|
|
265
|
+
"name": "latency_ms",
|
|
266
|
+
"type": "integer",
|
|
267
|
+
"primaryKey": false,
|
|
268
|
+
"notNull": false
|
|
269
|
+
},
|
|
270
|
+
"result": {
|
|
271
|
+
"name": "result",
|
|
272
|
+
"type": "jsonb",
|
|
273
|
+
"primaryKey": false,
|
|
274
|
+
"notNull": false
|
|
275
|
+
},
|
|
276
|
+
"source_id": {
|
|
277
|
+
"name": "source_id",
|
|
278
|
+
"type": "text",
|
|
279
|
+
"primaryKey": false,
|
|
280
|
+
"notNull": false
|
|
281
|
+
},
|
|
282
|
+
"source_label": {
|
|
283
|
+
"name": "source_label",
|
|
284
|
+
"type": "text",
|
|
285
|
+
"primaryKey": false,
|
|
286
|
+
"notNull": false
|
|
287
|
+
},
|
|
288
|
+
"timestamp": {
|
|
289
|
+
"name": "timestamp",
|
|
290
|
+
"type": "timestamp",
|
|
291
|
+
"primaryKey": false,
|
|
292
|
+
"notNull": true,
|
|
293
|
+
"default": "now()"
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
"indexes": {},
|
|
297
|
+
"foreignKeys": {
|
|
298
|
+
"health_check_runs_configuration_id_health_check_configurations_id_fk": {
|
|
299
|
+
"name": "health_check_runs_configuration_id_health_check_configurations_id_fk",
|
|
300
|
+
"tableFrom": "health_check_runs",
|
|
301
|
+
"tableTo": "health_check_configurations",
|
|
302
|
+
"columnsFrom": [
|
|
303
|
+
"configuration_id"
|
|
304
|
+
],
|
|
305
|
+
"columnsTo": [
|
|
306
|
+
"id"
|
|
307
|
+
],
|
|
308
|
+
"onDelete": "cascade",
|
|
309
|
+
"onUpdate": "no action"
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
"compositePrimaryKeys": {},
|
|
313
|
+
"uniqueConstraints": {},
|
|
314
|
+
"policies": {},
|
|
315
|
+
"checkConstraints": {},
|
|
316
|
+
"isRLSEnabled": false
|
|
317
|
+
},
|
|
318
|
+
"public.system_health_checks": {
|
|
319
|
+
"name": "system_health_checks",
|
|
320
|
+
"schema": "",
|
|
321
|
+
"columns": {
|
|
322
|
+
"system_id": {
|
|
323
|
+
"name": "system_id",
|
|
324
|
+
"type": "text",
|
|
325
|
+
"primaryKey": false,
|
|
326
|
+
"notNull": true
|
|
327
|
+
},
|
|
328
|
+
"configuration_id": {
|
|
329
|
+
"name": "configuration_id",
|
|
330
|
+
"type": "uuid",
|
|
331
|
+
"primaryKey": false,
|
|
332
|
+
"notNull": true
|
|
333
|
+
},
|
|
334
|
+
"enabled": {
|
|
335
|
+
"name": "enabled",
|
|
336
|
+
"type": "boolean",
|
|
337
|
+
"primaryKey": false,
|
|
338
|
+
"notNull": true,
|
|
339
|
+
"default": true
|
|
340
|
+
},
|
|
341
|
+
"state_thresholds": {
|
|
342
|
+
"name": "state_thresholds",
|
|
343
|
+
"type": "jsonb",
|
|
344
|
+
"primaryKey": false,
|
|
345
|
+
"notNull": false
|
|
346
|
+
},
|
|
347
|
+
"retention_config": {
|
|
348
|
+
"name": "retention_config",
|
|
349
|
+
"type": "jsonb",
|
|
350
|
+
"primaryKey": false,
|
|
351
|
+
"notNull": false
|
|
352
|
+
},
|
|
353
|
+
"satellite_ids": {
|
|
354
|
+
"name": "satellite_ids",
|
|
355
|
+
"type": "jsonb",
|
|
356
|
+
"primaryKey": false,
|
|
357
|
+
"notNull": false
|
|
358
|
+
},
|
|
359
|
+
"include_local": {
|
|
360
|
+
"name": "include_local",
|
|
361
|
+
"type": "boolean",
|
|
362
|
+
"primaryKey": false,
|
|
363
|
+
"notNull": true,
|
|
364
|
+
"default": true
|
|
365
|
+
},
|
|
366
|
+
"created_at": {
|
|
367
|
+
"name": "created_at",
|
|
368
|
+
"type": "timestamp",
|
|
369
|
+
"primaryKey": false,
|
|
370
|
+
"notNull": true,
|
|
371
|
+
"default": "now()"
|
|
372
|
+
},
|
|
373
|
+
"updated_at": {
|
|
374
|
+
"name": "updated_at",
|
|
375
|
+
"type": "timestamp",
|
|
376
|
+
"primaryKey": false,
|
|
377
|
+
"notNull": true,
|
|
378
|
+
"default": "now()"
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
"indexes": {},
|
|
382
|
+
"foreignKeys": {
|
|
383
|
+
"system_health_checks_configuration_id_health_check_configurations_id_fk": {
|
|
384
|
+
"name": "system_health_checks_configuration_id_health_check_configurations_id_fk",
|
|
385
|
+
"tableFrom": "system_health_checks",
|
|
386
|
+
"tableTo": "health_check_configurations",
|
|
387
|
+
"columnsFrom": [
|
|
388
|
+
"configuration_id"
|
|
389
|
+
],
|
|
390
|
+
"columnsTo": [
|
|
391
|
+
"id"
|
|
392
|
+
],
|
|
393
|
+
"onDelete": "cascade",
|
|
394
|
+
"onUpdate": "no action"
|
|
395
|
+
}
|
|
396
|
+
},
|
|
397
|
+
"compositePrimaryKeys": {
|
|
398
|
+
"system_health_checks_system_id_configuration_id_pk": {
|
|
399
|
+
"name": "system_health_checks_system_id_configuration_id_pk",
|
|
400
|
+
"columns": [
|
|
401
|
+
"system_id",
|
|
402
|
+
"configuration_id"
|
|
403
|
+
]
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
"uniqueConstraints": {},
|
|
407
|
+
"policies": {},
|
|
408
|
+
"checkConstraints": {},
|
|
409
|
+
"isRLSEnabled": false
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
"enums": {
|
|
413
|
+
"public.bucket_size": {
|
|
414
|
+
"name": "bucket_size",
|
|
415
|
+
"schema": "public",
|
|
416
|
+
"values": [
|
|
417
|
+
"hourly",
|
|
418
|
+
"daily"
|
|
419
|
+
]
|
|
420
|
+
},
|
|
421
|
+
"public.health_check_status": {
|
|
422
|
+
"name": "health_check_status",
|
|
423
|
+
"schema": "public",
|
|
424
|
+
"values": [
|
|
425
|
+
"healthy",
|
|
426
|
+
"unhealthy",
|
|
427
|
+
"degraded"
|
|
428
|
+
]
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
"schemas": {},
|
|
432
|
+
"sequences": {},
|
|
433
|
+
"roles": {},
|
|
434
|
+
"policies": {},
|
|
435
|
+
"views": {},
|
|
436
|
+
"_meta": {
|
|
437
|
+
"columns": {},
|
|
438
|
+
"schemas": {},
|
|
439
|
+
"tables": {}
|
|
440
|
+
}
|
|
441
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/healthcheck-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"checkstack": {
|
|
@@ -14,18 +14,18 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@checkstack/backend-api": "0.12.0",
|
|
17
|
-
"@checkstack/catalog-backend": "0.5.
|
|
17
|
+
"@checkstack/catalog-backend": "0.5.4",
|
|
18
18
|
"@checkstack/catalog-common": "1.4.1",
|
|
19
19
|
"@checkstack/command-backend": "0.1.19",
|
|
20
20
|
"@checkstack/common": "0.6.5",
|
|
21
|
-
"@checkstack/gitops-backend": "0.2.
|
|
21
|
+
"@checkstack/gitops-backend": "0.2.3",
|
|
22
22
|
"@checkstack/gitops-common": "0.2.0",
|
|
23
23
|
"@checkstack/healthcheck-common": "0.11.0",
|
|
24
24
|
"@checkstack/incident-common": "0.4.7",
|
|
25
25
|
"@checkstack/integration-backend": "0.1.19",
|
|
26
26
|
"@checkstack/maintenance-common": "0.4.9",
|
|
27
27
|
"@checkstack/queue-api": "0.2.13",
|
|
28
|
-
"@checkstack/satellite-backend": "0.2.
|
|
28
|
+
"@checkstack/satellite-backend": "0.2.13",
|
|
29
29
|
"@checkstack/signal-common": "0.1.9",
|
|
30
30
|
"@hono/zod-validator": "^0.7.6",
|
|
31
31
|
"drizzle-orm": "^0.45.0",
|
package/src/queue-executor.ts
CHANGED
|
@@ -101,6 +101,7 @@ export async function scheduleHealthCheck(props: {
|
|
|
101
101
|
*/
|
|
102
102
|
async function notifyStateChange(props: {
|
|
103
103
|
systemId: string;
|
|
104
|
+
systemName: string;
|
|
104
105
|
previousStatus: HealthCheckStatus;
|
|
105
106
|
newStatus: HealthCheckStatus;
|
|
106
107
|
catalogClient: CatalogClient;
|
|
@@ -110,6 +111,7 @@ async function notifyStateChange(props: {
|
|
|
110
111
|
}): Promise<void> {
|
|
111
112
|
const {
|
|
112
113
|
systemId,
|
|
114
|
+
systemName,
|
|
113
115
|
previousStatus,
|
|
114
116
|
newStatus,
|
|
115
117
|
catalogClient,
|
|
@@ -168,18 +170,18 @@ async function notifyStateChange(props: {
|
|
|
168
170
|
let importance: "info" | "warning" | "critical";
|
|
169
171
|
|
|
170
172
|
if (isRecovery) {
|
|
171
|
-
title =
|
|
173
|
+
title = `System health restored: ${systemName}`;
|
|
172
174
|
body =
|
|
173
|
-
|
|
175
|
+
`All health checks for **${systemName}** are now passing. The system has returned to normal operation.`;
|
|
174
176
|
importance = "info";
|
|
175
177
|
} else if (isUnhealthy) {
|
|
176
|
-
title =
|
|
177
|
-
body =
|
|
178
|
+
title = `System health critical: ${systemName}`;
|
|
179
|
+
body = `Health checks indicate **${systemName}** is unhealthy and may be down.`;
|
|
178
180
|
importance = "critical";
|
|
179
181
|
} else if (isDegraded) {
|
|
180
|
-
title =
|
|
182
|
+
title = `System health degraded: ${systemName}`;
|
|
181
183
|
body =
|
|
182
|
-
|
|
184
|
+
`Some health checks for **${systemName}** are failing. The system may be experiencing issues.`;
|
|
183
185
|
importance = "warning";
|
|
184
186
|
} else {
|
|
185
187
|
// No notification for healthy → healthy (if somehow missed above)
|
|
@@ -535,6 +537,7 @@ async function executeHealthCheckJob(props: {
|
|
|
535
537
|
if (newState.status !== previousStatus) {
|
|
536
538
|
await notifyStateChange({
|
|
537
539
|
systemId,
|
|
540
|
+
systemName,
|
|
538
541
|
previousStatus,
|
|
539
542
|
newStatus: newState.status,
|
|
540
543
|
catalogClient,
|
|
@@ -615,6 +618,7 @@ async function executeHealthCheckJob(props: {
|
|
|
615
618
|
if (newState.status !== previousStatus) {
|
|
616
619
|
await notifyStateChange({
|
|
617
620
|
systemId,
|
|
621
|
+
systemName,
|
|
618
622
|
previousStatus,
|
|
619
623
|
newStatus: newState.status,
|
|
620
624
|
catalogClient,
|
|
@@ -732,6 +736,7 @@ async function executeHealthCheckJob(props: {
|
|
|
732
736
|
if (newState.status !== previousStatus) {
|
|
733
737
|
await notifyStateChange({
|
|
734
738
|
systemId,
|
|
739
|
+
systemName,
|
|
735
740
|
previousStatus,
|
|
736
741
|
newStatus: newState.status,
|
|
737
742
|
catalogClient,
|
package/src/schema.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
uuid,
|
|
9
9
|
timestamp,
|
|
10
10
|
primaryKey,
|
|
11
|
-
|
|
11
|
+
unique,
|
|
12
12
|
} from "drizzle-orm/pg-core";
|
|
13
13
|
import type {
|
|
14
14
|
StateThresholds,
|
|
@@ -182,13 +182,15 @@ export const healthCheckAggregates = pgTable(
|
|
|
182
182
|
sourceLabel: text("source_label"),
|
|
183
183
|
},
|
|
184
184
|
(t) => ({
|
|
185
|
-
// Unique constraint includes sourceId for per-region aggregation
|
|
186
|
-
|
|
185
|
+
// Unique constraint includes sourceId for per-region aggregation.
|
|
186
|
+
// NULLS NOT DISTINCT ensures local runs (sourceId=NULL) correctly
|
|
187
|
+
// conflict-match instead of creating duplicate rows per hour.
|
|
188
|
+
bucketUnique: unique("health_check_aggregates_bucket_unique").on(
|
|
187
189
|
t.configurationId,
|
|
188
190
|
t.systemId,
|
|
189
191
|
t.bucketStart,
|
|
190
192
|
t.bucketSize,
|
|
191
193
|
t.sourceId,
|
|
192
|
-
),
|
|
194
|
+
).nullsNotDistinct(),
|
|
193
195
|
}),
|
|
194
196
|
);
|