@worker-manager/metrics 1.1.0 → 9.10.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.
Files changed (62) hide show
  1. package/README.md +6 -86
  2. package/dist/HistoryAdmin.d.ts +87 -23
  3. package/dist/HistoryAdmin.js +330 -21
  4. package/dist/HistoryAdmin.js.map +1 -1
  5. package/dist/HistoryStore.d.ts +9 -9
  6. package/dist/HistoryStore.js +0 -22
  7. package/dist/HistoryStore.js.map +1 -1
  8. package/dist/LatencySampler.d.ts +32 -27
  9. package/dist/LatencySampler.js +156 -55
  10. package/dist/LatencySampler.js.map +1 -1
  11. package/dist/LatencyStore.d.ts +3 -8
  12. package/dist/LatencyStore.js +0 -18
  13. package/dist/LatencyStore.js.map +1 -1
  14. package/dist/MetricsRecorder.d.ts +10 -34
  15. package/dist/MetricsRecorder.js +20 -30
  16. package/dist/MetricsRecorder.js.map +1 -1
  17. package/dist/RedisMetricsHistoryProvider.d.ts +17 -7
  18. package/dist/RedisMetricsHistoryProvider.js +136 -9
  19. package/dist/RedisMetricsHistoryProvider.js.map +1 -1
  20. package/dist/index.d.ts +2 -10
  21. package/dist/index.js +1 -10
  22. package/dist/index.js.map +1 -1
  23. package/dist/keys.d.ts +0 -7
  24. package/dist/keys.js +1 -23
  25. package/dist/keys.js.map +1 -1
  26. package/package.json +4 -14
  27. package/dist/RedisHistoryAdmin.d.ts +0 -95
  28. package/dist/RedisHistoryAdmin.js +0 -328
  29. package/dist/RedisHistoryAdmin.js.map +0 -1
  30. package/dist/RedisMetricsStore.d.ts +0 -27
  31. package/dist/RedisMetricsStore.js +0 -42
  32. package/dist/RedisMetricsStore.js.map +0 -1
  33. package/dist/StoreHistoryProvider.d.ts +0 -27
  34. package/dist/StoreHistoryProvider.js +0 -127
  35. package/dist/StoreHistoryProvider.js.map +0 -1
  36. package/dist/jobSources.d.ts +0 -97
  37. package/dist/jobSources.js +0 -248
  38. package/dist/jobSources.js.map +0 -1
  39. package/dist/postgres/PostgresMetricsHistoryProvider.d.ts +0 -37
  40. package/dist/postgres/PostgresMetricsHistoryProvider.js +0 -30
  41. package/dist/postgres/PostgresMetricsHistoryProvider.js.map +0 -1
  42. package/dist/postgres/PostgresMetricsStore.d.ts +0 -65
  43. package/dist/postgres/PostgresMetricsStore.js +0 -88
  44. package/dist/postgres/PostgresMetricsStore.js.map +0 -1
  45. package/dist/postgres/admin.d.ts +0 -31
  46. package/dist/postgres/admin.js +0 -178
  47. package/dist/postgres/admin.js.map +0 -1
  48. package/dist/postgres/connection.d.ts +0 -53
  49. package/dist/postgres/connection.js +0 -54
  50. package/dist/postgres/connection.js.map +0 -1
  51. package/dist/postgres/context.d.ts +0 -29
  52. package/dist/postgres/context.js +0 -76
  53. package/dist/postgres/context.js.map +0 -1
  54. package/dist/postgres/schema.d.ts +0 -26
  55. package/dist/postgres/schema.js +0 -148
  56. package/dist/postgres/schema.js.map +0 -1
  57. package/dist/postgres/stores.d.ts +0 -51
  58. package/dist/postgres/stores.js +0 -252
  59. package/dist/postgres/stores.js.map +0 -1
  60. package/dist/store.d.ts +0 -80
  61. package/dist/store.js +0 -3
  62. package/dist/store.js.map +0 -1
@@ -1,127 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StoreHistoryProvider = void 0;
4
- const histogram_1 = require("./histogram");
5
- const keys_1 = require("./keys");
6
- const MS_PER_HOUR = 3600000;
7
- /**
8
- * The `MetricsHistoryProvider` contract over any `MetricsStore`. Everything that decides what
9
- * a chart receives lives here, once: span clamping, day-start alignment, the empty-history
10
- * rule and percentile merging. The stores only fetch buckets, so a Redis and a PostgreSQL
11
- * board answer the same query with the same points.
12
- */
13
- class StoreHistoryProvider {
14
- constructor(store, retention) {
15
- this.retentionDays = retention.days;
16
- this.counters = store.counterStore(retention);
17
- this.latency = store.latencyStore(retention);
18
- this.admin = store.administration();
19
- }
20
- /** Backs the board's storage panel. See MetricsHistoryAdmin.stats. */
21
- async getUsage() {
22
- return this.admin.stats();
23
- }
24
- /** Backs the board's "clear history" action. See MetricsHistoryAdmin.purge. */
25
- async purge(options = {}) {
26
- return this.admin.purge(options);
27
- }
28
- async getHistory(query) {
29
- var _a;
30
- const queue = (_a = query.queue) !== null && _a !== void 0 ? _a : keys_1.GLOBAL_QUEUE;
31
- const days = this.daysFor(query);
32
- if (query.metric === 'queueage') {
33
- const ages = await this.latency.readQueueAge(queue, query.granularity, days);
34
- // Day points are stamped at the day's start, so an intraday `from` would drop the day
35
- // it falls in. Floored, exactly as the counter path below does it.
36
- const lowerBound = query.granularity === 'day' ? dayFloor(query.from) : query.from;
37
- return Object.keys(ages)
38
- .map((key) => ({
39
- ts: query.granularity === 'day' ? (0, keys_1.dayToStartMs)(key) : Number(key) * MS_PER_HOUR,
40
- value: ages[key],
41
- }))
42
- .filter((p) => p.ts >= lowerBound && p.ts <= query.to)
43
- .sort((a, b) => a.ts - b.ts);
44
- }
45
- if (query.granularity === 'day') {
46
- const totals = await this.counters.readDailyTotals(queue, query.metric, days);
47
- // Empty history only when no day in range was ever recorded (all fields missing).
48
- // A day with a stored 0 still counts as recorded -- otherwise the UI's empty
49
- // state would be unreachable once any data exists.
50
- if (totals.every((value) => value == null)) {
51
- return [];
52
- }
53
- return days
54
- .map((day, i) => { var _a; return ({ ts: (0, keys_1.dayToStartMs)(day), value: (_a = totals[i]) !== null && _a !== void 0 ? _a : 0 }); })
55
- .filter((p) => p.ts >= dayFloor(query.from) && p.ts <= query.to);
56
- }
57
- const hours = await this.counters.readHours(queue, query.metric, days);
58
- return Object.keys(hours)
59
- .map((field) => ({ ts: Number(field) * MS_PER_HOUR, value: hours[field] }))
60
- .filter((p) => p.ts >= query.from && p.ts <= query.to)
61
- .sort((a, b) => a.ts - b.ts);
62
- }
63
- async getLatency(query) {
64
- var _a;
65
- const queue = (_a = query.queue) !== null && _a !== void 0 ? _a : keys_1.GLOBAL_QUEUE;
66
- const days = this.daysFor(query);
67
- if (query.granularity === 'range') {
68
- // Percentiles don't merge: averaging per-day p95s isn't the same number as the p95 of
69
- // the whole range. Read the day tier's bucket vectors and merge them, then compute each
70
- // requested percentile once from the summed vector.
71
- const raw = await this.latency.readRange(queue, query.metric, 'day', days);
72
- let merged = (0, histogram_1.emptyVector)();
73
- for (const day of days) {
74
- const vector = raw[day];
75
- if (vector) {
76
- merged = (0, histogram_1.mergeVectors)(merged, vector);
77
- }
78
- }
79
- const count = (0, histogram_1.vectorTotal)(merged);
80
- if (count === 0) {
81
- return [];
82
- }
83
- const values = {};
84
- for (const p of query.percentiles) {
85
- values[String(p)] = (0, histogram_1.quantile)(merged, p);
86
- }
87
- return [{ ts: query.from, count: Math.round(count), values }];
88
- }
89
- const raw = await this.latency.readRange(queue, query.metric, query.granularity, days);
90
- // Same day-start alignment as getHistory: comparing a day bucket against a raw `from`
91
- // would drop the oldest day and leave this chart one bucket shorter than the throughput
92
- // chart drawn for the same range.
93
- const lowerBound = query.granularity === 'day' ? dayFloor(query.from) : query.from;
94
- const points = [];
95
- for (const key of Object.keys(raw)) {
96
- const ts = query.granularity === 'day' ? (0, keys_1.dayToStartMs)(key) : Number(key) * MS_PER_HOUR;
97
- if (ts < lowerBound || ts > query.to) {
98
- continue;
99
- }
100
- const vector = raw[key];
101
- const count = (0, histogram_1.vectorTotal)(vector);
102
- if (count === 0) {
103
- continue;
104
- }
105
- const values = {};
106
- for (const p of query.percentiles) {
107
- values[String(p)] = (0, histogram_1.quantile)(vector, p);
108
- }
109
- points.push({ ts, count: Math.round(count), values });
110
- }
111
- return points.sort((a, b) => a.ts - b.ts);
112
- }
113
- /**
114
- * Clamps the span to the retention window so an unbounded `from` (e.g. 0) can't make
115
- * dayRange produce an unbounded number of day buckets -- older data doesn't exist anyway.
116
- */
117
- daysFor(query) {
118
- const maxSpanMs = (this.retentionDays + 1) * 86400000;
119
- return (0, keys_1.dayRange)(Math.max(query.from, query.to - maxSpanMs), query.to);
120
- }
121
- }
122
- exports.StoreHistoryProvider = StoreHistoryProvider;
123
- function dayFloor(ms) {
124
- const d = new Date(ms);
125
- return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
126
- }
127
- //# sourceMappingURL=StoreHistoryProvider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"StoreHistoryProvider.js","sourceRoot":"","sources":["../src/StoreHistoryProvider.ts"],"names":[],"mappings":"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"}
@@ -1,97 +0,0 @@
1
- import type { BaseAdapter } from '@worker-manager/api/baseAdapter';
2
- import type { MetricsClient } from './connection';
3
- import { type PgQueryable } from './postgres/connection';
4
- /** The timing fields of one finished job, as the latency sampler needs them. */
5
- export interface FinishedJob {
6
- /** Creation time, `null` when the job carries none. */
7
- timestamp: number | null;
8
- processedOn: number;
9
- finishedOn: number;
10
- /** Attempts made, counting the one that finished. */
11
- attempts: number;
12
- }
13
- export interface FinishedJobs {
14
- /** Jobs that finished in the range, before any subsampling. */
15
- total: number;
16
- /** How many of them were selected for reading. `total / sampled` scales counts back up. */
17
- sampled: number;
18
- jobs: FinishedJob[];
19
- }
20
- /**
21
- * Where the sampler reads job timings from: the queue's own datastore, which is independent
22
- * of where history is stored. A PostgreSQL-backed queue can record into Redis and vice versa.
23
- */
24
- export interface JobSource {
25
- /**
26
- * Jobs whose finish time is in `(afterMs, upToMs]`. Above `maxSamples` a uniform subset is
27
- * read rather than the first N, which would bias towards the start of the range.
28
- */
29
- finishedJobs(afterMs: number, upToMs: number, maxSamples: number): Promise<FinishedJobs>;
30
- /**
31
- * Age of the oldest waiting job, 0 for an empty backlog, and `null` when the backlog could
32
- * not be read cleanly: a gap in the series reads as "not measured", a zero as "healthy".
33
- */
34
- oldestWaitingAge(now: number): Promise<number | null>;
35
- }
36
- interface AdapterWithKeys extends BaseAdapter {
37
- getQueueKey(set: string): string;
38
- }
39
- /**
40
- * A BullMQ queue stored in Redis, read with the same commands BullMQ itself writes.
41
- *
42
- * BullMQ's moveToFinished does `ZADD targetSet, timestamp, jobId` and writes the same value to
43
- * finishedOn, so the completed and failed sets are sorted sets scored by finish time.
44
- */
45
- export declare class RedisJobSource implements JobSource {
46
- private readonly redis;
47
- private readonly adapter;
48
- constructor(redis: MetricsClient, adapter: AdapterWithKeys);
49
- finishedJobs(afterMs: number, upToMs: number, maxSamples: number): Promise<FinishedJobs>;
50
- /**
51
- * The backlog is not all in one place. `wait` holds it while the queue is running, but
52
- * pausing RENAMEs that list to `paused` and routes new jobs there, and anything added with
53
- * a priority goes to the `prioritized` sorted set instead, which can leave `wait`
54
- * permanently empty. Reading only `wait` reports a healthy zero for a queue that is badly
55
- * backed up, which is the opposite of what this gauge is for, so all three are consulted
56
- * and the worst age wins.
57
- */
58
- oldestWaitingAge(now: number): Promise<number | null>;
59
- }
60
- /**
61
- * A BullMQ v6 queue stored in PostgreSQL. BullMQ keeps every job in one `job` table with a
62
- * `state` column, and indexes finished jobs on `(queue, state, finished_at_ms)`, which is the
63
- * exact shape of the range scan below.
64
- */
65
- export declare class PostgresJobSource implements JobSource {
66
- private readonly pool;
67
- private readonly queueName;
68
- private readonly job;
69
- constructor(pool: PgQueryable, schema: string, queueName: string);
70
- /**
71
- * One round trip. The selection is the same evenly spaced pick the Redis source makes,
72
- * done in SQL so a busy tick transfers at most `maxSamples` rows: row `i` of `total` is
73
- * kept when it is `floor(k * total / max)` for some `k`, which integer arithmetic decides
74
- * without enumerating the `k`s.
75
- */
76
- finishedJobs(afterMs: number, upToMs: number, maxSamples: number): Promise<FinishedJobs>;
77
- /**
78
- * Paused and prioritized are not physical states here: a paused queue's jobs stay
79
- * `waiting`, and a prioritized job is a waiting job with `priority > 0`. The ready index
80
- * orders waiting jobs by `(priority, seq)`, so the three ends read below are index probes,
81
- * not a scan of the backlog: the next job to run, the far end of the prioritized range, and
82
- * the far end of the unprioritized range, which holds the oldest job of a LIFO queue.
83
- * Like the Redis prioritized read, this is an approximation that never reads the whole set.
84
- */
85
- oldestWaitingAge(now: number): Promise<number | null>;
86
- }
87
- /**
88
- * The PostgreSQL pool behind a BullMQ v6 queue, or `null` for anything else.
89
- *
90
- * This is a structural probe of BullMQAdapter's queue and BullMQ's backend rather than a
91
- * public API of either, so every step is optional and a shape it does not recognise simply
92
- * reads as "not PostgreSQL". The pool is used directly rather than through the backend's
93
- * `query()`, which parks a query forever once the queue starts closing and would leave a
94
- * recorder tick hanging on a queue that was just removed from the board.
95
- */
96
- export declare function postgresSourceOf(adapter: BaseAdapter): PostgresJobSource | null;
97
- export {};
@@ -1,248 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PostgresJobSource = exports.RedisJobSource = void 0;
4
- exports.postgresSourceOf = postgresSourceOf;
5
- const connection_1 = require("./postgres/connection");
6
- /**
7
- * A BullMQ queue stored in Redis, read with the same commands BullMQ itself writes.
8
- *
9
- * BullMQ's moveToFinished does `ZADD targetSet, timestamp, jobId` and writes the same value to
10
- * finishedOn, so the completed and failed sets are sorted sets scored by finish time.
11
- */
12
- class RedisJobSource {
13
- constructor(redis, adapter) {
14
- this.redis = redis;
15
- this.adapter = adapter;
16
- }
17
- async finishedJobs(afterMs, upToMs, maxSamples) {
18
- var _a;
19
- const ids = [];
20
- for (const set of ['completed', 'failed']) {
21
- const found = await this.redis.zrangebyscore(this.adapter.getQueueKey(set), `(${afterMs}`, upToMs);
22
- ids.push(...found);
23
- }
24
- if (ids.length === 0) {
25
- return { total: 0, sampled: 0, jobs: [] };
26
- }
27
- // The id list is one cheap round trip; the HMGETs are the real cost.
28
- const selected = ids.length > maxSamples ? sampleUniformly(ids, maxSamples) : ids;
29
- const pipeline = this.redis.pipeline();
30
- for (const id of selected) {
31
- pipeline.hmget(this.adapter.getQueueKey(String(id)), 'timestamp', 'processedOn', 'finishedOn',
32
- // BullMQ 5 counts attempts in `atm`; `attemptsMade` is the pre-v5 name and is read
33
- // as a fallback exactly the way Job.fromJSON does.
34
- 'atm', 'attemptsMade');
35
- }
36
- const rows = await pipeline.exec();
37
- const jobs = [];
38
- for (const row of rows !== null && rows !== void 0 ? rows : []) {
39
- const values = row === null || row === void 0 ? void 0 : row[1];
40
- if (!values) {
41
- continue;
42
- }
43
- const [timestamp, processedOn, finishedOn, atm, attemptsMade] = values;
44
- if (!processedOn || !finishedOn) {
45
- continue;
46
- }
47
- jobs.push({
48
- timestamp: timestamp ? Number(timestamp) : null,
49
- processedOn: Number(processedOn),
50
- finishedOn: Number(finishedOn),
51
- attempts: Number((_a = atm !== null && atm !== void 0 ? atm : attemptsMade) !== null && _a !== void 0 ? _a : 0),
52
- });
53
- }
54
- return { total: ids.length, sampled: selected.length, jobs };
55
- }
56
- /**
57
- * The backlog is not all in one place. `wait` holds it while the queue is running, but
58
- * pausing RENAMEs that list to `paused` and routes new jobs there, and anything added with
59
- * a priority goes to the `prioritized` sorted set instead, which can leave `wait`
60
- * permanently empty. Reading only `wait` reports a healthy zero for a queue that is badly
61
- * backed up, which is the opposite of what this gauge is for, so all three are consulted
62
- * and the worst age wins.
63
- */
64
- async oldestWaitingAge(now) {
65
- var _a;
66
- const candidates = await this.redis
67
- .pipeline()
68
- // BullMQ LPUSHes to the wait list and workers RPOPLPUSH from it, so the tail is oldest.
69
- .lrange(this.adapter.getQueueKey('wait'), -1, -1)
70
- .lrange(this.adapter.getQueueKey('paused'), -1, -1)
71
- // The prioritized set is scored by priority, not by time, so neither end is guaranteed
72
- // to hold the oldest job. Both ends are an approximation, and a cheap one: the true
73
- // oldest would mean fetching the whole set every tick.
74
- // String indices: ioredis v6 types `zrange`'s stop arg as string-only (Redis coerces
75
- // either way), so numeric literals no longer typecheck. '0'/'-1' are the first/last members.
76
- .zrange(this.adapter.getQueueKey('prioritized'), '0', '0')
77
- .zrange(this.adapter.getQueueKey('prioritized'), '-1', '-1')
78
- .exec();
79
- // A pipeline reports failures per command: a Redis error arrives in the entry's error
80
- // slot next to a null result, rather than as a throw. Reading only the result slot turns
81
- // a failed read into an empty backlog and records an age of 0, which is the most
82
- // reassuring number this gauge can produce, at the moment it is least entitled to.
83
- if (!candidates || candidates.some(([error]) => error)) {
84
- return null;
85
- }
86
- const ids = new Set();
87
- for (const entry of candidates) {
88
- for (const id of (_a = entry[1]) !== null && _a !== void 0 ? _a : []) {
89
- ids.add(String(id));
90
- }
91
- }
92
- if (ids.size === 0) {
93
- return 0;
94
- }
95
- const stamps = this.redis.pipeline();
96
- for (const id of ids) {
97
- stamps.hget(this.adapter.getQueueKey(id), 'timestamp');
98
- }
99
- const rows = await stamps.exec();
100
- // Same reasoning: a failed timestamp read does not zero the gauge, it understates it,
101
- // which is the same wrong-but-reassuring answer in a quieter form.
102
- if (!rows || rows.some(([error]) => error)) {
103
- return null;
104
- }
105
- let oldest = 0;
106
- for (const row of rows) {
107
- const raw = row[1];
108
- if (!raw) {
109
- continue;
110
- }
111
- const enqueuedAt = Number(raw);
112
- if (!Number.isFinite(enqueuedAt)) {
113
- continue;
114
- }
115
- oldest = Math.max(oldest, now - enqueuedAt);
116
- }
117
- return Math.max(0, oldest);
118
- }
119
- }
120
- exports.RedisJobSource = RedisJobSource;
121
- /**
122
- * A BullMQ v6 queue stored in PostgreSQL. BullMQ keeps every job in one `job` table with a
123
- * `state` column, and indexes finished jobs on `(queue, state, finished_at_ms)`, which is the
124
- * exact shape of the range scan below.
125
- */
126
- class PostgresJobSource {
127
- constructor(pool, schema, queueName) {
128
- this.pool = pool;
129
- this.queueName = queueName;
130
- this.job = `${(0, connection_1.quoteIdentifier)(schema)}.job`;
131
- }
132
- /**
133
- * One round trip. The selection is the same evenly spaced pick the Redis source makes,
134
- * done in SQL so a busy tick transfers at most `maxSamples` rows: row `i` of `total` is
135
- * kept when it is `floor(k * total / max)` for some `k`, which integer arithmetic decides
136
- * without enumerating the `k`s.
137
- */
138
- async finishedJobs(afterMs, upToMs, maxSamples) {
139
- var _a;
140
- const max = Math.max(1, Math.floor(maxSamples));
141
- const { rows } = await this.pool.query(`WITH finished AS (
142
- SELECT added_at_ms, processed_at_ms, finished_at_ms, attempts_made,
143
- row_number() OVER (ORDER BY finished_at_ms, id) - 1 AS i,
144
- count(*) OVER () AS total
145
- FROM ${this.job}
146
- WHERE queue = $1
147
- AND state IN ('completed', 'failed')
148
- AND finished_at_ms > $2
149
- AND finished_at_ms <= $3
150
- )
151
- SELECT added_at_ms, processed_at_ms, finished_at_ms, attempts_made, total
152
- FROM finished
153
- WHERE total <= $4
154
- OR ((i * $4 + total - 1) / total) * total / $4 = i`, [this.queueName, afterMs, upToMs, max]);
155
- if (rows.length === 0) {
156
- return { total: 0, sampled: 0, jobs: [] };
157
- }
158
- const total = Number(rows[0].total);
159
- const jobs = [];
160
- for (const row of rows) {
161
- if (row.processed_at_ms == null || row.finished_at_ms == null) {
162
- continue;
163
- }
164
- jobs.push({
165
- timestamp: row.added_at_ms == null ? null : Number(row.added_at_ms),
166
- processedOn: Number(row.processed_at_ms),
167
- finishedOn: Number(row.finished_at_ms),
168
- attempts: Number((_a = row.attempts_made) !== null && _a !== void 0 ? _a : 0),
169
- });
170
- }
171
- return { total, sampled: rows.length, jobs };
172
- }
173
- /**
174
- * Paused and prioritized are not physical states here: a paused queue's jobs stay
175
- * `waiting`, and a prioritized job is a waiting job with `priority > 0`. The ready index
176
- * orders waiting jobs by `(priority, seq)`, so the three ends read below are index probes,
177
- * not a scan of the backlog: the next job to run, the far end of the prioritized range, and
178
- * the far end of the unprioritized range, which holds the oldest job of a LIFO queue.
179
- * Like the Redis prioritized read, this is an approximation that never reads the whole set.
180
- */
181
- async oldestWaitingAge(now) {
182
- var _a;
183
- const { rows } = await this.pool.query(`SELECT min(added_at_ms) AS oldest FROM (
184
- (SELECT added_at_ms FROM ${this.job}
185
- WHERE queue = $1 AND state = 'waiting' ORDER BY priority, seq LIMIT 1)
186
- UNION ALL
187
- (SELECT added_at_ms FROM ${this.job}
188
- WHERE queue = $1 AND state = 'waiting' ORDER BY priority DESC, seq DESC LIMIT 1)
189
- UNION ALL
190
- (SELECT added_at_ms FROM ${this.job}
191
- WHERE queue = $1 AND state = 'waiting' AND priority = 0 ORDER BY seq DESC LIMIT 1)
192
- ) AS ends`, [this.queueName]);
193
- const oldest = (_a = rows[0]) === null || _a === void 0 ? void 0 : _a.oldest;
194
- if (oldest == null) {
195
- return 0;
196
- }
197
- return Math.max(0, now - Number(oldest));
198
- }
199
- }
200
- exports.PostgresJobSource = PostgresJobSource;
201
- /**
202
- * The PostgreSQL pool behind a BullMQ v6 queue, or `null` for anything else.
203
- *
204
- * This is a structural probe of BullMQAdapter's queue and BullMQ's backend rather than a
205
- * public API of either, so every step is optional and a shape it does not recognise simply
206
- * reads as "not PostgreSQL". The pool is used directly rather than through the backend's
207
- * `query()`, which parks a query forever once the queue starts closing and would leave a
208
- * recorder tick hanging on a queue that was just removed from the board.
209
- */
210
- function postgresSourceOf(adapter) {
211
- var _a, _b, _c, _d, _e;
212
- const queue = adapter.queue;
213
- if (!queue || typeof queue.getBackend !== 'function') {
214
- return null;
215
- }
216
- let backend;
217
- try {
218
- backend = queue.getBackend();
219
- }
220
- catch {
221
- return null;
222
- }
223
- const pool = (_a = backend === null || backend === void 0 ? void 0 : backend.connection) === null || _a === void 0 ? void 0 : _a.pool;
224
- if (!pool || typeof pool.query !== 'function') {
225
- return null;
226
- }
227
- const schema = (_d = (_b = backend === null || backend === void 0 ? void 0 : backend.schema) !== null && _b !== void 0 ? _b : (_c = backend === null || backend === void 0 ? void 0 : backend.connection) === null || _c === void 0 ? void 0 : _c.schema) !== null && _d !== void 0 ? _d : 'bullmq';
228
- const name = (_e = backend === null || backend === void 0 ? void 0 : backend.queueName) !== null && _e !== void 0 ? _e : queue.name;
229
- if (typeof schema !== 'string' || typeof name !== 'string') {
230
- return null;
231
- }
232
- try {
233
- return new PostgresJobSource(pool, schema, name);
234
- }
235
- catch {
236
- return null; // a schema name BullMQ itself would have refused
237
- }
238
- }
239
- /** Evenly spaced pick across the list, which preserves the distribution's shape. */
240
- function sampleUniformly(ids, target) {
241
- const stride = ids.length / target;
242
- const out = [];
243
- for (let i = 0; i < target; i++) {
244
- out.push(ids[Math.floor(i * stride)]);
245
- }
246
- return out;
247
- }
248
- //# sourceMappingURL=jobSources.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"jobSources.js","sourceRoot":"","sources":["../src/jobSources.ts"],"names":[],"mappings":"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"}
@@ -1,37 +0,0 @@
1
- import type { Retention } from '../store';
2
- import { StoreHistoryProvider } from '../StoreHistoryProvider';
3
- import type { PostgresConnection } from './connection';
4
- import { PostgresMetricsStore } from './PostgresMetricsStore';
5
- interface RetentionOptions {
6
- /** Should mirror the recorder's retention. Only used to bound the query span. */
7
- retention?: Partial<Retention>;
8
- retentionDays?: number;
9
- }
10
- export type PostgresMetricsHistoryProviderOptions = RetentionOptions & ({
11
- /** A `pg.Pool`, a node-postgres pool config, or a connection string. */
12
- connection: PostgresConnection;
13
- /** Must match the recorder's store. See `PostgresMetricsStoreOptions`. */
14
- schema?: string;
15
- tablePrefix?: string;
16
- /** See `PostgresMetricsStoreOptions.migrate`. */
17
- migrate?: boolean;
18
- onError?: (error: Error) => void;
19
- store?: never;
20
- } | {
21
- /** A store shared with the recorder. Left open on `disconnect()`. */
22
- store: PostgresMetricsStore;
23
- connection?: never;
24
- schema?: never;
25
- tablePrefix?: never;
26
- migrate?: never;
27
- onError?: never;
28
- });
29
- /** Serves the board's history charts and storage panel from the PostgreSQL store. */
30
- export declare class PostgresMetricsHistoryProvider extends StoreHistoryProvider {
31
- readonly store: PostgresMetricsStore;
32
- private readonly ownsStore;
33
- constructor(opts: PostgresMetricsHistoryProviderOptions);
34
- /** Ends the pool behind a store this provider built. A store or pool handed in is left open. */
35
- disconnect(): Promise<void>;
36
- }
37
- export {};
@@ -1,30 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PostgresMetricsHistoryProvider = void 0;
4
- const MetricsRecorder_1 = require("../MetricsRecorder");
5
- const StoreHistoryProvider_1 = require("../StoreHistoryProvider");
6
- const PostgresMetricsStore_1 = require("./PostgresMetricsStore");
7
- /** Serves the board's history charts and storage panel from the PostgreSQL store. */
8
- class PostgresMetricsHistoryProvider extends StoreHistoryProvider_1.StoreHistoryProvider {
9
- constructor(opts) {
10
- var _a;
11
- const store = (_a = opts.store) !== null && _a !== void 0 ? _a : new PostgresMetricsStore_1.PostgresMetricsStore({
12
- connection: opts.connection,
13
- schema: opts.schema,
14
- tablePrefix: opts.tablePrefix,
15
- migrate: opts.migrate,
16
- onError: opts.onError,
17
- });
18
- super(store, (0, MetricsRecorder_1.resolveRetention)(opts));
19
- this.store = store;
20
- this.ownsStore = !opts.store;
21
- }
22
- /** Ends the pool behind a store this provider built. A store or pool handed in is left open. */
23
- async disconnect() {
24
- if (this.ownsStore) {
25
- await this.store.close();
26
- }
27
- }
28
- }
29
- exports.PostgresMetricsHistoryProvider = PostgresMetricsHistoryProvider;
30
- //# sourceMappingURL=PostgresMetricsHistoryProvider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PostgresMetricsHistoryProvider.js","sourceRoot":"","sources":["../../src/postgres/PostgresMetricsHistoryProvider.ts"],"names":[],"mappings":";;;AAAA,wDAAsD;AAEtD,kEAA+D;AAE/D,iEAA8D;AAgC9D,qFAAqF;AACrF,MAAa,8BAA+B,SAAQ,2CAAoB;IAItE,YAAY,IAA2C;;QACrD,MAAM,KAAK,GACT,MAAA,IAAI,CAAC,KAAK,mCACV,IAAI,2CAAoB,CAAC;YACvB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;QACL,KAAK,CAAC,KAAK,EAAE,IAAA,kCAAgB,EAAC,IAAI,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;IAC/B,CAAC;IAED,gGAAgG;IAChG,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;CACF;AAzBD,wEAyBC"}
@@ -1,65 +0,0 @@
1
- import type { CounterStore, HistoryAdministration, LatencyStorage, MetricsStore, Retention } from '../store';
2
- import { type PgPool, type PostgresConnection } from './connection';
3
- import { type MetricsTables } from './schema';
4
- export interface PostgresMetricsStoreOptions {
5
- /** A `pg.Pool`, a node-postgres pool config, or a connection string. */
6
- connection: PostgresConnection;
7
- /**
8
- * Schema holding the tables. Defaults to a `schema` key on a pool config (so the object
9
- * given to BullMQ's PostgreSQL backend can be reused), then to `public`. Created on
10
- * migration when missing.
11
- */
12
- schema?: string;
13
- /** Prepended to every table name. Defaults to `bull_board_metrics_`. */
14
- tablePrefix?: string;
15
- /**
16
- * Create or upgrade the tables before the first query. Off by default, in which case the
17
- * first query checks the schema version instead and fails with instructions when the tables
18
- * are missing: in deployments where the application role has no DDL rights, run
19
- * `migratePostgresMetrics()` from a deploy step.
20
- */
21
- migrate?: boolean;
22
- /**
23
- * Errors from idle pooled connections of a pool this store created (a server restart, a
24
- * dropped connection). Without a listener node-postgres would crash the process on them.
25
- */
26
- onError?: (error: Error) => void;
27
- }
28
- /**
29
- * History in PostgreSQL, for boards whose queues live on BullMQ's PostgreSQL backend and have
30
- * no Redis at all. Same tiers, retention, rollup and idempotency as the Redis store; see the
31
- * package README for the schema and sizing.
32
- */
33
- export declare class PostgresMetricsStore implements MetricsStore {
34
- readonly pool: PgPool;
35
- readonly tables: MetricsTables;
36
- readonly jobClient: null;
37
- private readonly owned;
38
- private readonly shouldMigrate;
39
- private readiness;
40
- private closed;
41
- private readonly ctx;
42
- constructor(opts: PostgresMetricsStoreOptions);
43
- /** Creates or upgrades the tables now. Idempotent and safe to race. */
44
- migrate(): Promise<void>;
45
- /**
46
- * Memoized, but not on failure: a database that was unreachable at startup is retried on
47
- * the next query instead of poisoning the store for the life of the process.
48
- */
49
- ready(): Promise<void>;
50
- counterStore(retention: Retention): CounterStore;
51
- latencyStore(retention: Retention): LatencyStorage;
52
- administration(): HistoryAdministration;
53
- /** Ends the pool if this store created it. A pool handed in is left to its owner. */
54
- close(): Promise<void>;
55
- }
56
- export interface MigratePostgresMetricsOptions {
57
- connection: PostgresConnection;
58
- schema?: string;
59
- tablePrefix?: string;
60
- }
61
- /**
62
- * Deploy-step form of `migrate: true`: creates or upgrades the metrics tables and returns.
63
- * A pool handed in is left open; one built from a config or string is ended afterwards.
64
- */
65
- export declare function migratePostgresMetrics(opts: MigratePostgresMetricsOptions): Promise<void>;