@miragon/pulse-analytics-client 0.0.0-bootstrap.0 → 0.21.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.
Files changed (200) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -3
  3. package/dist/index.d.ts +12 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +14 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/metric-names.d.ts +43 -0
  8. package/dist/metric-names.d.ts.map +1 -0
  9. package/dist/metric-names.js +53 -0
  10. package/dist/metric-names.js.map +1 -0
  11. package/dist/metrics-contract-labels.test.d.ts +2 -0
  12. package/dist/metrics-contract-labels.test.d.ts.map +1 -0
  13. package/dist/metrics-contract-labels.test.js +169 -0
  14. package/dist/metrics-contract-labels.test.js.map +1 -0
  15. package/dist/metrics-contract.test.d.ts +2 -0
  16. package/dist/metrics-contract.test.d.ts.map +1 -0
  17. package/dist/metrics-contract.test.js +247 -0
  18. package/dist/metrics-contract.test.js.map +1 -0
  19. package/dist/prometheus-client.test.d.ts +2 -0
  20. package/dist/prometheus-client.test.d.ts.map +1 -0
  21. package/dist/prometheus-client.test.js +265 -0
  22. package/dist/prometheus-client.test.js.map +1 -0
  23. package/dist/prometheus.d.ts +100 -0
  24. package/dist/prometheus.d.ts.map +1 -0
  25. package/dist/prometheus.js +295 -0
  26. package/dist/prometheus.js.map +1 -0
  27. package/dist/prometheus.test.d.ts +2 -0
  28. package/dist/prometheus.test.d.ts.map +1 -0
  29. package/dist/prometheus.test.js +54 -0
  30. package/dist/prometheus.test.js.map +1 -0
  31. package/dist/promql-labels.test-support.d.ts +53 -0
  32. package/dist/promql-labels.test-support.d.ts.map +1 -0
  33. package/dist/promql-labels.test-support.js +237 -0
  34. package/dist/promql-labels.test-support.js.map +1 -0
  35. package/dist/promql-labels.test.d.ts +2 -0
  36. package/dist/promql-labels.test.d.ts.map +1 -0
  37. package/dist/promql-labels.test.js +190 -0
  38. package/dist/promql-labels.test.js.map +1 -0
  39. package/dist/promql-parse.test-support.d.ts +57 -0
  40. package/dist/promql-parse.test-support.d.ts.map +1 -0
  41. package/dist/promql-parse.test-support.js +284 -0
  42. package/dist/promql-parse.test-support.js.map +1 -0
  43. package/dist/promql-reading-rules.test-support.d.ts +29 -0
  44. package/dist/promql-reading-rules.test-support.d.ts.map +1 -0
  45. package/dist/promql-reading-rules.test-support.js +79 -0
  46. package/dist/promql-reading-rules.test-support.js.map +1 -0
  47. package/dist/promql-reading-rules.test.d.ts +2 -0
  48. package/dist/promql-reading-rules.test.d.ts.map +1 -0
  49. package/dist/promql-reading-rules.test.js +61 -0
  50. package/dist/promql-reading-rules.test.js.map +1 -0
  51. package/dist/promql-sources.test-support.d.ts +29 -0
  52. package/dist/promql-sources.test-support.d.ts.map +1 -0
  53. package/dist/promql-sources.test-support.js +112 -0
  54. package/dist/promql-sources.test-support.js.map +1 -0
  55. package/dist/promql-sources.test.d.ts +2 -0
  56. package/dist/promql-sources.test.d.ts.map +1 -0
  57. package/dist/promql-sources.test.js +93 -0
  58. package/dist/promql-sources.test.js.map +1 -0
  59. package/dist/queries/as-of.test.d.ts +2 -0
  60. package/dist/queries/as-of.test.d.ts.map +1 -0
  61. package/dist/queries/as-of.test.js +80 -0
  62. package/dist/queries/as-of.test.js.map +1 -0
  63. package/dist/queries/cluster-compare.d.ts +62 -0
  64. package/dist/queries/cluster-compare.d.ts.map +1 -0
  65. package/dist/queries/cluster-compare.js +70 -0
  66. package/dist/queries/cluster-compare.js.map +1 -0
  67. package/dist/queries/cluster-compare.test.d.ts +2 -0
  68. package/dist/queries/cluster-compare.test.d.ts.map +1 -0
  69. package/dist/queries/cluster-compare.test.js +81 -0
  70. package/dist/queries/cluster-compare.test.js.map +1 -0
  71. package/dist/queries/dashboard.d.ts +60 -0
  72. package/dist/queries/dashboard.d.ts.map +1 -0
  73. package/dist/queries/dashboard.js +292 -0
  74. package/dist/queries/dashboard.js.map +1 -0
  75. package/dist/queries/dashboard.test.d.ts +2 -0
  76. package/dist/queries/dashboard.test.d.ts.map +1 -0
  77. package/dist/queries/dashboard.test.js +423 -0
  78. package/dist/queries/dashboard.test.js.map +1 -0
  79. package/dist/queries/element.d.ts +68 -0
  80. package/dist/queries/element.d.ts.map +1 -0
  81. package/dist/queries/element.js +98 -0
  82. package/dist/queries/element.js.map +1 -0
  83. package/dist/queries/element.test.d.ts +2 -0
  84. package/dist/queries/element.test.d.ts.map +1 -0
  85. package/dist/queries/element.test.js +105 -0
  86. package/dist/queries/element.test.js.map +1 -0
  87. package/dist/queries/engine-compare.d.ts +52 -0
  88. package/dist/queries/engine-compare.d.ts.map +1 -0
  89. package/dist/queries/engine-compare.js +57 -0
  90. package/dist/queries/engine-compare.js.map +1 -0
  91. package/dist/queries/engine-compare.test.d.ts +2 -0
  92. package/dist/queries/engine-compare.test.d.ts.map +1 -0
  93. package/dist/queries/engine-compare.test.js +159 -0
  94. package/dist/queries/engine-compare.test.js.map +1 -0
  95. package/dist/queries/engine-landscape.d.ts +92 -0
  96. package/dist/queries/engine-landscape.d.ts.map +1 -0
  97. package/dist/queries/engine-landscape.js +183 -0
  98. package/dist/queries/engine-landscape.js.map +1 -0
  99. package/dist/queries/engine-landscape.test.d.ts +2 -0
  100. package/dist/queries/engine-landscape.test.d.ts.map +1 -0
  101. package/dist/queries/engine-landscape.test.js +171 -0
  102. package/dist/queries/engine-landscape.test.js.map +1 -0
  103. package/dist/queries/failures.d.ts +33 -0
  104. package/dist/queries/failures.d.ts.map +1 -0
  105. package/dist/queries/failures.js +31 -0
  106. package/dist/queries/failures.js.map +1 -0
  107. package/dist/queries/health.d.ts +77 -0
  108. package/dist/queries/health.d.ts.map +1 -0
  109. package/dist/queries/health.js +126 -0
  110. package/dist/queries/health.js.map +1 -0
  111. package/dist/queries/health.test.d.ts +2 -0
  112. package/dist/queries/health.test.d.ts.map +1 -0
  113. package/dist/queries/health.test.js +187 -0
  114. package/dist/queries/health.test.js.map +1 -0
  115. package/dist/queries/helpers.d.ts +184 -0
  116. package/dist/queries/helpers.d.ts.map +1 -0
  117. package/dist/queries/helpers.js +219 -0
  118. package/dist/queries/helpers.js.map +1 -0
  119. package/dist/queries/helpers.test.d.ts +2 -0
  120. package/dist/queries/helpers.test.d.ts.map +1 -0
  121. package/dist/queries/helpers.test.js +53 -0
  122. package/dist/queries/helpers.test.js.map +1 -0
  123. package/dist/queries/index.d.ts +19 -0
  124. package/dist/queries/index.d.ts.map +1 -0
  125. package/dist/queries/index.js +10 -0
  126. package/dist/queries/index.js.map +1 -0
  127. package/dist/queries/performance.d.ts +103 -0
  128. package/dist/queries/performance.d.ts.map +1 -0
  129. package/dist/queries/performance.js +173 -0
  130. package/dist/queries/performance.js.map +1 -0
  131. package/dist/queries/performance.test.d.ts +2 -0
  132. package/dist/queries/performance.test.d.ts.map +1 -0
  133. package/dist/queries/performance.test.js +265 -0
  134. package/dist/queries/performance.test.js.map +1 -0
  135. package/dist/queries/version-compare.d.ts +41 -0
  136. package/dist/queries/version-compare.d.ts.map +1 -0
  137. package/dist/queries/version-compare.js +44 -0
  138. package/dist/queries/version-compare.js.map +1 -0
  139. package/dist/queries/version-compare.test.d.ts +2 -0
  140. package/dist/queries/version-compare.test.d.ts.map +1 -0
  141. package/dist/queries/version-compare.test.js +162 -0
  142. package/dist/queries/version-compare.test.js.map +1 -0
  143. package/dist/queries/windows.d.ts +40 -0
  144. package/dist/queries/windows.d.ts.map +1 -0
  145. package/dist/queries/windows.js +56 -0
  146. package/dist/queries/windows.js.map +1 -0
  147. package/dist/query-honesty.test.d.ts +2 -0
  148. package/dist/query-honesty.test.d.ts.map +1 -0
  149. package/dist/query-honesty.test.js +294 -0
  150. package/dist/query-honesty.test.js.map +1 -0
  151. package/dist/query-scenarios.test-support.d.ts +49 -0
  152. package/dist/query-scenarios.test-support.d.ts.map +1 -0
  153. package/dist/query-scenarios.test-support.js +146 -0
  154. package/dist/query-scenarios.test-support.js.map +1 -0
  155. package/dist/schemas/cluster-compare.d.ts +11 -0
  156. package/dist/schemas/cluster-compare.d.ts.map +1 -0
  157. package/dist/schemas/cluster-compare.js +35 -0
  158. package/dist/schemas/cluster-compare.js.map +1 -0
  159. package/dist/schemas/engine-compare.d.ts +10 -0
  160. package/dist/schemas/engine-compare.d.ts.map +1 -0
  161. package/dist/schemas/engine-compare.js +27 -0
  162. package/dist/schemas/engine-compare.js.map +1 -0
  163. package/dist/schemas/engine-landscape.d.ts +5 -0
  164. package/dist/schemas/engine-landscape.d.ts.map +1 -0
  165. package/dist/schemas/engine-landscape.js +8 -0
  166. package/dist/schemas/engine-landscape.js.map +1 -0
  167. package/dist/schemas/failures.d.ts +8 -0
  168. package/dist/schemas/failures.d.ts.map +1 -0
  169. package/dist/schemas/failures.js +9 -0
  170. package/dist/schemas/failures.js.map +1 -0
  171. package/dist/schemas/health.d.ts +5 -0
  172. package/dist/schemas/health.d.ts.map +1 -0
  173. package/dist/schemas/health.js +6 -0
  174. package/dist/schemas/health.js.map +1 -0
  175. package/dist/schemas/index.d.ts +10 -0
  176. package/dist/schemas/index.d.ts.map +1 -0
  177. package/dist/schemas/index.js +10 -0
  178. package/dist/schemas/index.js.map +1 -0
  179. package/dist/schemas/path.d.ts +15 -0
  180. package/dist/schemas/path.d.ts.map +1 -0
  181. package/dist/schemas/path.js +21 -0
  182. package/dist/schemas/path.js.map +1 -0
  183. package/dist/schemas/performance.d.ts +23 -0
  184. package/dist/schemas/performance.d.ts.map +1 -0
  185. package/dist/schemas/performance.js +21 -0
  186. package/dist/schemas/performance.js.map +1 -0
  187. package/dist/schemas/shared.d.ts +34 -0
  188. package/dist/schemas/shared.d.ts.map +1 -0
  189. package/dist/schemas/shared.js +34 -0
  190. package/dist/schemas/shared.js.map +1 -0
  191. package/dist/schemas/version-compare.d.ts +10 -0
  192. package/dist/schemas/version-compare.d.ts.map +1 -0
  193. package/dist/schemas/version-compare.js +25 -0
  194. package/dist/schemas/version-compare.js.map +1 -0
  195. package/dist/widgets.d.ts +138 -0
  196. package/dist/widgets.d.ts.map +1 -0
  197. package/dist/widgets.js +2 -0
  198. package/dist/widgets.js.map +1 -0
  199. package/metrics-contract.json +174 -0
  200. package/package.json +72 -5
@@ -0,0 +1,183 @@
1
+ import { engineMatcher, selector, } from "../prometheus.js";
2
+ import { METRIC_NAMES as M } from "../metric-names.js";
3
+ import { asOfNow, engineState } from "./helpers.js";
4
+ /** A per-key gauge summed per (engine, key) — `incidents_open` also carries a type. */
5
+ const byKey = (gauge, sel) => `sum by (engine_id, process_definition_key)(${engineState(gauge, sel)})`;
6
+ /**
7
+ * Cross-engine landscape: what runs where, how much of it, and which engines
8
+ * carry a backlog.
9
+ *
10
+ * Deliberately NOT an engine-vs-engine scoreboard. Rates (failure rate,
11
+ * incident rate, duration) aggregated per engine measure that engine's PROCESS
12
+ * MIX, not the engine: an engine hosting an inherently error-prone process
13
+ * reads "unhealthy" while running perfectly. So this query reports the two
14
+ * things that survive a different mix per engine:
15
+ *
16
+ * 1. Absolute counts (running instances, open incidents, failed jobs) — they
17
+ * say where work and trouble physically sit, which is what an operator
18
+ * acts on, and they stay additive across engines.
19
+ * 2. The engine-owned backlog gauges (`jobs_executable`, `jobs_suspended`,
20
+ * `jobs_due_future`, `external_tasks_open`), whose contract labels are
21
+ * `engine_id` ONLY. With no process dimension there is no mix to confound
22
+ * them, so these genuinely do rank engines against each other.
23
+ *
24
+ * The inventory matrix then names the one place a KPI comparison IS sound: a
25
+ * process definition key present on two or more engines (`sharedProcessKeys`)
26
+ * — the drill-down {@link engineCompare} requires.
27
+ *
28
+ * Pass `engine` as the array of CONFIGURED engine ids to also surface engines
29
+ * that report nothing (`reporting: false`); without it the landscape can only
30
+ * show engines Prometheus has series for.
31
+ */
32
+ export async function engineLandscape(ch, params = {}) {
33
+ const asOf = asOfNow();
34
+ const sel = selector(engineMatcher(params.engine));
35
+ // One `sum by (…)` per gauge over its node-folded rows — the joining
36
+ // happens in TS.
37
+ const [deployed, running, incidents, failedJobs, executable, suspended, dueFuture, externalTasks,] = await Promise.all([
38
+ ch.instant(byKey(M.processDefinitionsDeployed, sel)),
39
+ ch.instant(byKey(M.processInstancesRunning, sel)),
40
+ ch.instant(byKey(M.incidentsOpen, sel)),
41
+ ch.instant(byKey(M.jobsFailed, sel)),
42
+ ch.instant(engineState(M.jobsExecutable, sel)),
43
+ ch.instant(engineState(M.jobsSuspended, sel)),
44
+ ch.instant(engineState(M.jobsDueFuture, sel)),
45
+ ch.instant(engineState(M.externalTasksOpen, sel)),
46
+ ]);
47
+ const deployedCells = cells(deployed);
48
+ const runningCells = cells(running);
49
+ const incidentCells = cells(incidents);
50
+ const failedCells = cells(failedJobs);
51
+ // A key counts as present on an engine when it is deployed there OR still has
52
+ // live state there — a key undeployed while instances keep running would
53
+ // otherwise drop out of the matrix that is supposed to explain them.
54
+ const presence = [...deployedCells, ...runningCells, ...incidentCells, ...failedCells];
55
+ // Every engine id seen anywhere, plus the ones the caller declared — so a
56
+ // silent engine gets a row instead of vanishing from the overview.
57
+ const reporting = new Set([deployed, running, incidents, failedJobs, executable, suspended, dueFuture, externalTasks]
58
+ .flat()
59
+ .map((s) => s.metric.engine_id)
60
+ .filter((id) => !!id));
61
+ const engineIds = [...new Set([...expectedEngineIds(params.engine), ...reporting])].sort();
62
+ const keysOn = (engineId) => [
63
+ ...new Set(presence.filter((c) => c.engineId === engineId).map((c) => c.processDefinitionKey)),
64
+ ];
65
+ const enginesWithKey = (key) => [
66
+ ...new Set(presence.filter((c) => c.processDefinitionKey === key).map((c) => c.engineId)),
67
+ ].sort();
68
+ const engines = engineIds.map((engineId) => {
69
+ if (!reporting.has(engineId))
70
+ return silentEngine(engineId);
71
+ const keys = keysOn(engineId);
72
+ return {
73
+ engineId,
74
+ reporting: true,
75
+ runningInstances: sumBy(runningCells, (c) => c.engineId === engineId),
76
+ openIncidents: sumBy(incidentCells, (c) => c.engineId === engineId),
77
+ failedJobs: sumBy(failedCells, (c) => c.engineId === engineId),
78
+ executableJobs: engineValue(executable, engineId),
79
+ suspendedJobs: engineValue(suspended, engineId),
80
+ jobsDueFuture: engineValue(dueFuture, engineId),
81
+ openExternalTasks: engineValue(externalTasks, engineId),
82
+ deployedDefinitionKeys: keys.length,
83
+ exclusiveDefinitionKeys: keys.filter((k) => enginesWithKey(k).length === 1).length,
84
+ };
85
+ });
86
+ const processes = [
87
+ ...new Set(presence.map((c) => c.processDefinitionKey)),
88
+ ]
89
+ .map((processDefinitionKey) => {
90
+ const on = enginesWithKey(processDefinitionKey);
91
+ const runningByEngine = {};
92
+ for (const engineId of on) {
93
+ const value = sumBy(runningCells, (c) => c.engineId === engineId && c.processDefinitionKey === processDefinitionKey);
94
+ if (value !== 0)
95
+ runningByEngine[engineId] = value;
96
+ }
97
+ const forKey = (list) => sumBy(list, (c) => c.processDefinitionKey === processDefinitionKey);
98
+ return {
99
+ processDefinitionKey,
100
+ engineIds: on,
101
+ shared: on.length > 1,
102
+ runningByEngine,
103
+ runningTotal: forKey(runningCells),
104
+ openIncidentsTotal: forKey(incidentCells),
105
+ failedJobsTotal: forKey(failedCells),
106
+ };
107
+ })
108
+ // Shared keys lead: they are the only rows offering a valid comparison.
109
+ .sort((a, b) => Number(b.shared) - Number(a.shared) ||
110
+ b.runningTotal - a.runningTotal ||
111
+ a.processDefinitionKey.localeCompare(b.processDefinitionKey));
112
+ const sharedProcessKeys = processes.filter((p) => p.shared).map((p) => p.processDefinitionKey);
113
+ const reportingEngineCount = engines.filter((e) => e.reporting).length;
114
+ /** A total over the reporting engines; unknown (null) while none reports. */
115
+ const total = (list) => (reportingEngineCount > 0 ? sumBy(list, () => true) : null);
116
+ return {
117
+ asOf,
118
+ engines,
119
+ processes,
120
+ sharedProcessKeys,
121
+ totals: {
122
+ engineCount: engines.length,
123
+ reportingEngineCount,
124
+ processKeyCount: processes.length,
125
+ sharedProcessKeyCount: sharedProcessKeys.length,
126
+ runningInstances: total(runningCells),
127
+ openIncidents: total(incidentCells),
128
+ failedJobs: total(failedCells),
129
+ },
130
+ };
131
+ }
132
+ /**
133
+ * The row of a declared engine that sent no series at all: every count is
134
+ * unknown. A row of zeros would read as an idle, healthy engine.
135
+ */
136
+ function silentEngine(engineId) {
137
+ return {
138
+ engineId,
139
+ reporting: false,
140
+ runningInstances: null,
141
+ openIncidents: null,
142
+ failedJobs: null,
143
+ executableJobs: null,
144
+ suspendedJobs: null,
145
+ jobsDueFuture: null,
146
+ openExternalTasks: null,
147
+ deployedDefinitionKeys: null,
148
+ exclusiveDefinitionKeys: null,
149
+ };
150
+ }
151
+ /** The engine ids the caller declared, so silent engines still get a row. */
152
+ function expectedEngineIds(engine) {
153
+ if (engine === undefined || engine === null)
154
+ return [];
155
+ const ids = Array.isArray(engine) ? engine : [engine];
156
+ return ids.filter((id) => id.length > 0);
157
+ }
158
+ /**
159
+ * `(engine_id, process_definition_key)` samples as flat cells, dropping any
160
+ * sample missing either label. Values are rounded — every source gauge is an
161
+ * integer count.
162
+ *
163
+ * The `sum by (engine_id, process_definition_key)` above already folds every
164
+ * extra dimension away (`incidents_open` carries an `incident_type`), so
165
+ * Prometheus returns exactly ONE sample per pair. The `sumBy` callers therefore
166
+ * add across pairs — all keys of one engine, or all engines of one key — never
167
+ * within a pair.
168
+ */
169
+ function cells(samples) {
170
+ const out = [];
171
+ for (const s of samples) {
172
+ const engineId = s.metric.engine_id;
173
+ const processDefinitionKey = s.metric.process_definition_key;
174
+ if (!engineId || !processDefinitionKey)
175
+ continue;
176
+ out.push({ engineId, processDefinitionKey, value: Math.round(s.value) });
177
+ }
178
+ return out;
179
+ }
180
+ const sumBy = (list, match) => list.reduce((sum, c) => (match(c) ? sum + c.value : sum), 0);
181
+ /** Value of the `sum by (engine_id)` sample for one engine, or 0 when absent. */
182
+ const engineValue = (samples, engineId) => Math.round(samples.find((s) => s.metric.engine_id === engineId)?.value ?? 0);
183
+ //# sourceMappingURL=engine-landscape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-landscape.js","sourceRoot":"","sources":["../../src/queries/engine-landscape.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=engine-landscape.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-landscape.test.d.ts","sourceRoot":"","sources":["../../src/queries/engine-landscape.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,171 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { engineLandscape } from "./engine-landscape.js";
3
+ const cell = (engine_id, process_definition_key, value) => ({
4
+ metric: { engine_id, process_definition_key },
5
+ value,
6
+ });
7
+ const gauge = (engine_id, value) => ({ metric: { engine_id }, value });
8
+ /**
9
+ * Two engines with a partly overlapping process landscape: `order` runs on
10
+ * both (the only comparable key), `invoice` only on prod-a, `onboarding` only
11
+ * on prod-b.
12
+ */
13
+ function mockClient() {
14
+ const instant = vi.fn(async (q) => {
15
+ if (q.includes("process_definitions_deployed")) {
16
+ return [
17
+ cell("prod-a", "order", 3),
18
+ cell("prod-a", "invoice", 1),
19
+ cell("prod-b", "order", 2),
20
+ cell("prod-b", "onboarding", 1),
21
+ ];
22
+ }
23
+ if (q.includes("process_instances_running")) {
24
+ return [
25
+ cell("prod-a", "order", 5),
26
+ cell("prod-a", "invoice", 2),
27
+ cell("prod-b", "order", 7),
28
+ cell("prod-b", "onboarding", 4),
29
+ ];
30
+ }
31
+ if (q.includes("incidents_open")) {
32
+ // `sum by (engine_id, process_definition_key)` folds `incident_type`
33
+ // away, so there is one sample per pair however many types produced it.
34
+ return [cell("prod-a", "order", 3), cell("prod-b", "onboarding", 4)];
35
+ }
36
+ if (q.includes("jobs_failed"))
37
+ return [cell("prod-a", "order", 3)];
38
+ if (q.includes("jobs_executable"))
39
+ return [gauge("prod-a", 12), gauge("prod-b", 40)];
40
+ if (q.includes("jobs_suspended"))
41
+ return [gauge("prod-b", 2)];
42
+ if (q.includes("jobs_due_future"))
43
+ return [gauge("prod-a", 8)];
44
+ if (q.includes("external_tasks_open"))
45
+ return [gauge("prod-b", 6)];
46
+ return [];
47
+ });
48
+ const ch = { instant };
49
+ return { ch, instant };
50
+ }
51
+ describe("engineLandscape", () => {
52
+ it("reports absolute load and the engine-owned backlog per engine", async () => {
53
+ const { ch } = mockClient();
54
+ const res = await engineLandscape(ch);
55
+ expect(res.engines).toEqual([
56
+ {
57
+ engineId: "prod-a",
58
+ reporting: true,
59
+ runningInstances: 7,
60
+ openIncidents: 3,
61
+ failedJobs: 3,
62
+ executableJobs: 12,
63
+ suspendedJobs: 0,
64
+ jobsDueFuture: 8,
65
+ openExternalTasks: 0,
66
+ deployedDefinitionKeys: 2,
67
+ exclusiveDefinitionKeys: 1, // invoice
68
+ },
69
+ {
70
+ engineId: "prod-b",
71
+ reporting: true,
72
+ runningInstances: 11,
73
+ openIncidents: 4,
74
+ failedJobs: 0,
75
+ executableJobs: 40,
76
+ suspendedJobs: 2,
77
+ jobsDueFuture: 0,
78
+ openExternalTasks: 6,
79
+ deployedDefinitionKeys: 2,
80
+ exclusiveDefinitionKeys: 1, // onboarding
81
+ },
82
+ ]);
83
+ });
84
+ it("marks only the process deployed on more than one engine as shared", async () => {
85
+ const { ch } = mockClient();
86
+ const res = await engineLandscape(ch);
87
+ expect(res.sharedProcessKeys).toEqual(["order"]);
88
+ // Shared keys sort first, then by running instances descending.
89
+ expect(res.processes.map((p) => p.processDefinitionKey)).toEqual([
90
+ "order",
91
+ "onboarding",
92
+ "invoice",
93
+ ]);
94
+ expect(res.processes[0]).toEqual({
95
+ processDefinitionKey: "order",
96
+ engineIds: ["prod-a", "prod-b"],
97
+ shared: true,
98
+ runningByEngine: { "prod-a": 5, "prod-b": 7 },
99
+ runningTotal: 12,
100
+ openIncidentsTotal: 3,
101
+ failedJobsTotal: 3,
102
+ });
103
+ expect(res.processes[2]).toMatchObject({
104
+ processDefinitionKey: "invoice",
105
+ engineIds: ["prod-a"],
106
+ shared: false,
107
+ });
108
+ });
109
+ it("totals the landscape without double counting", async () => {
110
+ const { ch } = mockClient();
111
+ const res = await engineLandscape(ch);
112
+ expect(res.totals).toEqual({
113
+ engineCount: 2,
114
+ reportingEngineCount: 2,
115
+ processKeyCount: 3,
116
+ sharedProcessKeyCount: 1,
117
+ runningInstances: 18,
118
+ openIncidents: 7,
119
+ failedJobs: 3,
120
+ });
121
+ });
122
+ it("keeps a configured engine that reports no metrics visible", async () => {
123
+ const { ch } = mockClient();
124
+ const res = await engineLandscape(ch, { engine: ["prod-a", "prod-b", "prod-c"] });
125
+ const silent = res.engines.find((e) => e.engineId === "prod-c");
126
+ // Unknown, not zero: a row of 0s would read as an idle, healthy engine.
127
+ expect(silent).toEqual({
128
+ engineId: "prod-c",
129
+ reporting: false,
130
+ runningInstances: null,
131
+ openIncidents: null,
132
+ failedJobs: null,
133
+ executableJobs: null,
134
+ suspendedJobs: null,
135
+ jobsDueFuture: null,
136
+ openExternalTasks: null,
137
+ deployedDefinitionKeys: null,
138
+ exclusiveDefinitionKeys: null,
139
+ });
140
+ // The totals add up the engines that report.
141
+ expect(res.totals).toMatchObject({
142
+ engineCount: 3,
143
+ reportingEngineCount: 2,
144
+ runningInstances: 18,
145
+ openIncidents: 7,
146
+ });
147
+ });
148
+ it("scopes every query by the engine filter", async () => {
149
+ const { ch, instant } = mockClient();
150
+ await engineLandscape(ch, { engine: ["prod-a", "prod-b"] });
151
+ const queries = instant.mock.calls.map((c) => c[0]);
152
+ expect(queries).toHaveLength(8);
153
+ expect(queries.every((q) => q.includes('{engine_id=~"prod-a|prod-b"}'))).toBe(true);
154
+ // The four process-scoped metrics group by both labels, the four
155
+ // engine-owned gauges by engine_id only.
156
+ expect(queries.filter((q) => q.includes("by (engine_id, process_definition_key)"))).toHaveLength(4);
157
+ });
158
+ it("returns an empty landscape instead of failing when nothing reports", async () => {
159
+ const res = await engineLandscape({ instant: async () => [] });
160
+ expect(res.engines).toEqual([]);
161
+ expect(res.processes).toEqual([]);
162
+ expect(res.totals).toMatchObject({
163
+ engineCount: 0,
164
+ processKeyCount: 0,
165
+ runningInstances: null,
166
+ openIncidents: null,
167
+ failedJobs: null,
168
+ });
169
+ });
170
+ });
171
+ //# sourceMappingURL=engine-landscape.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-landscape.test.js","sourceRoot":"","sources":["../../src/queries/engine-landscape.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { type EngineFilterInput, type PrometheusClient } from "../prometheus.js";
2
+ /**
3
+ * One group of currently-open incidents. Only what the `camunda_incidents_open`
4
+ * gauge carries: no message, activity, timestamps or instance ids exist on it.
5
+ */
6
+ export interface ErrorPatternRow {
7
+ incident_type: string;
8
+ process_definition_key: string;
9
+ incident_count: number;
10
+ }
11
+ export interface FailedInstancesResult {
12
+ /** The engine ids covered; `null` = every engine Prometheus holds (unscoped library call). */
13
+ engines: string[] | null;
14
+ /** Open-incident groups, largest first, capped at `maxResults`. */
15
+ patterns: ErrorPatternRow[];
16
+ }
17
+ /**
18
+ * Currently-open incident groups, from the `camunda_incidents_open` state
19
+ * gauge — grouped by `incident_type` + definition. Point-in-time ("what is
20
+ * failing now"), so it is robust regardless of how the data arrived (live or
21
+ * a backdated/bulk import, which no counter window sees).
22
+ *
23
+ * The gauge carries no incident message, activity id, timestamps or instance
24
+ * ids, so the rows carry none either. For the actual failed instances drill
25
+ * in with `camunda7_list_incidents` / `camunda7_query_historic_incidents`.
26
+ */
27
+ export declare function findFailedInstances(ch: PrometheusClient, params: {
28
+ processDefinitionKey?: string;
29
+ incidentType?: string;
30
+ maxResults: number;
31
+ engine?: EngineFilterInput;
32
+ }): Promise<FailedInstancesResult>;
33
+ //# sourceMappingURL=failures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failures.d.ts","sourceRoot":"","sources":["../../src/queries/failures.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAA;AAIzB;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,8FAA8F;IAC9F,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IACxB,mEAAmE;IACnE,QAAQ,EAAE,eAAe,EAAE,CAAA;CAC5B;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,gBAAgB,EACpB,MAAM,EAAE;IACN,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAC3B,GACA,OAAO,CAAC,qBAAqB,CAAC,CAwBhC"}
@@ -0,0 +1,31 @@
1
+ import { engineIdsOf, engineMatcher, escapeLabelValue, selector, } from "../prometheus.js";
2
+ import { METRIC_NAMES as M } from "../metric-names.js";
3
+ import { engineState } from "./helpers.js";
4
+ /**
5
+ * Currently-open incident groups, from the `camunda_incidents_open` state
6
+ * gauge — grouped by `incident_type` + definition. Point-in-time ("what is
7
+ * failing now"), so it is robust regardless of how the data arrived (live or
8
+ * a backdated/bulk import, which no counter window sees).
9
+ *
10
+ * The gauge carries no incident message, activity id, timestamps or instance
11
+ * ids, so the rows carry none either. For the actual failed instances drill
12
+ * in with `camunda7_list_incidents` / `camunda7_query_historic_incidents`.
13
+ */
14
+ export async function findFailedInstances(ch, params) {
15
+ const limit = Math.max(1, Math.floor(params.maxResults));
16
+ const sel = selector(params.processDefinitionKey
17
+ ? `process_definition_key="${escapeLabelValue(params.processDefinitionKey)}"`
18
+ : undefined, params.incidentType ? `incident_type="${escapeLabelValue(params.incidentType)}"` : undefined, engineMatcher(params.engine));
19
+ const samples = await ch.instant(`sum by (process_definition_key, incident_type)(${engineState(M.incidentsOpen, sel)})`);
20
+ const patterns = samples
21
+ .map((s) => ({
22
+ incident_type: s.metric.incident_type ?? "",
23
+ process_definition_key: s.metric.process_definition_key ?? "",
24
+ incident_count: Math.round(s.value),
25
+ }))
26
+ .filter((r) => r.incident_count > 0)
27
+ .sort((a, b) => b.incident_count - a.incident_count)
28
+ .slice(0, limit);
29
+ return { engines: engineIdsOf(params.engine), patterns };
30
+ }
31
+ //# sourceMappingURL=failures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failures.js","sourceRoot":"","sources":["../../src/queries/failures.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,QAAQ,GAGT,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,YAAY,IAAI,CAAC,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAmB1C;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAoB,EACpB,MAKC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAA;IACxD,MAAM,GAAG,GAAG,QAAQ,CAClB,MAAM,CAAC,oBAAoB;QACzB,CAAC,CAAC,2BAA2B,gBAAgB,CAAC,MAAM,CAAC,oBAAoB,CAAC,GAAG;QAC7E,CAAC,CAAC,SAAS,EACb,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,kBAAkB,gBAAgB,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAC5F,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAC7B,CAAA;IAED,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAC9B,kDAAkD,WAAW,CAAC,CAAC,CAAC,aAAa,EAAE,GAAG,CAAC,GAAG,CACvF,CAAA;IAED,MAAM,QAAQ,GAAG,OAAO;SACrB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC,aAAa,IAAI,EAAE;QAC3C,sBAAsB,EAAE,CAAC,CAAC,MAAM,CAAC,sBAAsB,IAAI,EAAE;QAC7D,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;KACpC,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC;SACnC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,GAAG,CAAC,CAAC,cAAc,CAAC;SACnD,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IAClB,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAA;AAC1D,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { type EngineFilterInput, type PrometheusClient } from "../prometheus.js";
2
+ export interface HealthCount {
3
+ label: string;
4
+ count: number;
5
+ }
6
+ export interface HealthAlert {
7
+ name: string;
8
+ severity: string;
9
+ scope: string;
10
+ }
11
+ /**
12
+ * Name pattern (RE2) of the alert rules this module ships
13
+ * (`playground/docker/prometheus/alerts.yml`). An alert WITHOUT an
14
+ * `engine_id` label — a pipeline-level rule such as `CibSevenEngineNoMetrics`
15
+ * — only counts when it matches this pattern: in a shared Prometheus every
16
+ * other engine-less alert belongs to somebody else.
17
+ */
18
+ export declare const ENGINE_ALERT_NAME_PATTERN = "CibSeven.+";
19
+ /**
20
+ * How {@link engineHealth} decides `status`, in words — carried in every
21
+ * result (`statusRule`) and the tool description, so no reader mistakes this
22
+ * alert-based verdict for camunda7_show_engine_health's incident-count one:
23
+ * the two judge different data by different rules and may disagree for the
24
+ * same engine (500 open incidents without a firing critical alert stay
25
+ * "degraded" here).
26
+ */
27
+ export declare const ENGINE_HEALTH_STATUS_RULE = "From Prometheus, over the engines in scope: unknown when none of them reports metrics; critical only while a severity=critical alert fires for them (fleet-wide also an engine-less CibSeven* alert); degraded with any such firing alert, dead job, open incident or an engine in scope that reports nothing; else healthy.";
28
+ export interface EngineHealthResult {
29
+ status: "healthy" | "degraded" | "critical" | "unknown";
30
+ /** How `status` was decided ({@link ENGINE_HEALTH_STATUS_RULE}). */
31
+ statusRule: string;
32
+ /** The engine ids judged; `null` = every engine Prometheus holds (unscoped library call). */
33
+ engines: string[] | null;
34
+ /**
35
+ * Engines with a live engine-state gauge — Prometheus' 5-minute staleness
36
+ * window makes "present" mean "reported within the last minutes".
37
+ */
38
+ reportingEngines: string[];
39
+ /**
40
+ * Engines in scope that report nothing: the metrics plugin or collector is
41
+ * down, or the engine's `ENGINE_ID` does not match. Every count below reads
42
+ * 0 for them — not because they are idle.
43
+ */
44
+ silentEngines: string[];
45
+ runningInstances: number;
46
+ runningByDefinition: HealthCount[];
47
+ openIncidents: number;
48
+ openIncidentsByType: HealthCount[];
49
+ deadJobs: number;
50
+ executableJobs: number;
51
+ suspendedJobs: number;
52
+ openUserTasks: number;
53
+ unassignedUserTasks: number;
54
+ openExternalTasks: number;
55
+ deployedDefinitionKeys: number;
56
+ firingAlerts: HealthAlert[];
57
+ pendingAlerts: HealthAlert[];
58
+ }
59
+ /**
60
+ * Live operational health of the engine(s), from the point-in-time gauges plus
61
+ * Prometheus' own `ALERTS` series. A one-call ops snapshot: running WIP, open
62
+ * incidents, dead jobs, job/task/external-task backlog, and which alert rules
63
+ * are firing/pending.
64
+ *
65
+ * Absence is not health: the engine-only gauges (`jobs_executable`,
66
+ * `external_tasks_open`) double as the presence probe, so an engine that
67
+ * sends nothing — or an id that matches no series — reads `unknown` (none in
68
+ * scope reports) or lands in `silentEngines` (degrading the verdict), never
69
+ * `healthy`. `includeFleetAlerts` (default: exactly when `engine` is
70
+ * omitted) adds the module's engine-less alerts — set it when `engine` lists
71
+ * the whole configured fleet.
72
+ */
73
+ export declare function engineHealth(ch: PrometheusClient, params: {
74
+ engine?: EngineFilterInput;
75
+ includeFleetAlerts?: boolean;
76
+ }): Promise<EngineHealthResult>;
77
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/queries/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EAEtB,MAAM,kBAAkB,CAAA;AAIzB,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,eAAe,CAAA;AAErD;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,iUAC0R,CAAA;AAEhU,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAA;IACvD,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAA;IAClB,6FAA6F;IAC7F,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;IACxB;;;OAGG;IACH,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B;;;;OAIG;IACH,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IACxB,mBAAmB,EAAE,WAAW,EAAE,CAAA;IAClC,aAAa,EAAE,MAAM,CAAA;IACrB,mBAAmB,EAAE,WAAW,EAAE,CAAA;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,iBAAiB,EAAE,MAAM,CAAA;IACzB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,YAAY,EAAE,WAAW,EAAE,CAAA;IAC3B,aAAa,EAAE,WAAW,EAAE,CAAA;CAC7B;AAqCD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,gBAAgB,EACpB,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAE,GACnE,OAAO,CAAC,kBAAkB,CAAC,CAqF7B"}