@lde/distribution-monitor 0.1.13 → 0.1.15
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/dist/schema.d.ts +101 -96
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +17 -13
- package/dist/service.d.ts +0 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +0 -10
- package/dist/store.d.ts +0 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +45 -21
- package/dist/types.d.ts +1 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/schema.d.ts
CHANGED
|
@@ -99,102 +99,107 @@ export declare const observations: import("drizzle-orm/pg-core").PgTableWithColu
|
|
|
99
99
|
dialect: "pg";
|
|
100
100
|
}>;
|
|
101
101
|
/**
|
|
102
|
-
*
|
|
102
|
+
* Latest observation per monitor, keyed by `monitor`. Kept current by an upsert
|
|
103
|
+
* on every write (see `PostgresObservationStore.store`) rather than a
|
|
104
|
+
* materialized view: reads are always current, and there is no periodic
|
|
105
|
+
* full-table `REFRESH` to fall behind, contend on locks, or scan the whole
|
|
106
|
+
* `observations` history every cycle.
|
|
103
107
|
*/
|
|
104
|
-
export declare const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
108
|
+
export declare const latestObservations: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
109
|
+
name: "latest_observations";
|
|
110
|
+
schema: undefined;
|
|
111
|
+
columns: {
|
|
112
|
+
id: import("drizzle-orm/pg-core").PgBuildColumn<"latest_observations", import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").PgUUIDBuilder>, {
|
|
113
|
+
name: string;
|
|
114
|
+
tableName: "latest_observations";
|
|
115
|
+
dataType: "string uuid";
|
|
116
|
+
data: string;
|
|
117
|
+
driverParam: string;
|
|
118
|
+
notNull: true;
|
|
119
|
+
hasDefault: false;
|
|
120
|
+
isPrimaryKey: false;
|
|
121
|
+
isAutoincrement: false;
|
|
122
|
+
hasRuntimeDefault: false;
|
|
123
|
+
enumValues: undefined;
|
|
124
|
+
identity: undefined;
|
|
125
|
+
generated: undefined;
|
|
126
|
+
}>;
|
|
127
|
+
monitor: import("drizzle-orm/pg-core").PgBuildColumn<"latest_observations", import("drizzle-orm/pg-core").SetIsPrimaryKey<import("drizzle-orm/pg-core").PgTextBuilder<[string, ...string[]]>>, {
|
|
128
|
+
name: string;
|
|
129
|
+
tableName: "latest_observations";
|
|
130
|
+
dataType: "string";
|
|
131
|
+
data: string;
|
|
132
|
+
driverParam: string;
|
|
133
|
+
notNull: true;
|
|
134
|
+
hasDefault: false;
|
|
135
|
+
isPrimaryKey: false;
|
|
136
|
+
isAutoincrement: false;
|
|
137
|
+
hasRuntimeDefault: false;
|
|
138
|
+
enumValues: undefined;
|
|
139
|
+
identity: undefined;
|
|
140
|
+
generated: undefined;
|
|
141
|
+
}>;
|
|
142
|
+
observedAt: import("drizzle-orm/pg-core").PgBuildColumn<"latest_observations", import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").PgTimestampBuilder>, {
|
|
143
|
+
name: string;
|
|
144
|
+
tableName: "latest_observations";
|
|
145
|
+
dataType: "object date";
|
|
146
|
+
data: Date;
|
|
147
|
+
driverParam: string;
|
|
148
|
+
notNull: true;
|
|
149
|
+
hasDefault: false;
|
|
150
|
+
isPrimaryKey: false;
|
|
151
|
+
isAutoincrement: false;
|
|
152
|
+
hasRuntimeDefault: false;
|
|
153
|
+
enumValues: undefined;
|
|
154
|
+
identity: undefined;
|
|
155
|
+
generated: undefined;
|
|
156
|
+
}>;
|
|
157
|
+
success: import("drizzle-orm/pg-core").PgBuildColumn<"latest_observations", import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").PgBooleanBuilder>, {
|
|
158
|
+
name: string;
|
|
159
|
+
tableName: "latest_observations";
|
|
160
|
+
dataType: "boolean";
|
|
161
|
+
data: boolean;
|
|
162
|
+
driverParam: boolean;
|
|
163
|
+
notNull: true;
|
|
164
|
+
hasDefault: false;
|
|
165
|
+
isPrimaryKey: false;
|
|
166
|
+
isAutoincrement: false;
|
|
167
|
+
hasRuntimeDefault: false;
|
|
168
|
+
enumValues: undefined;
|
|
169
|
+
identity: undefined;
|
|
170
|
+
generated: undefined;
|
|
171
|
+
}>;
|
|
172
|
+
responseTimeMs: import("drizzle-orm/pg-core").PgBuildColumn<"latest_observations", import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").PgIntegerBuilder>, {
|
|
173
|
+
name: string;
|
|
174
|
+
tableName: "latest_observations";
|
|
175
|
+
dataType: "number int32";
|
|
176
|
+
data: number;
|
|
177
|
+
driverParam: string | number;
|
|
178
|
+
notNull: true;
|
|
179
|
+
hasDefault: false;
|
|
180
|
+
isPrimaryKey: false;
|
|
181
|
+
isAutoincrement: false;
|
|
182
|
+
hasRuntimeDefault: false;
|
|
183
|
+
enumValues: undefined;
|
|
184
|
+
identity: undefined;
|
|
185
|
+
generated: undefined;
|
|
186
|
+
}>;
|
|
187
|
+
errorMessage: import("drizzle-orm/pg-core").PgBuildColumn<"latest_observations", import("drizzle-orm/pg-core").PgTextBuilder<[string, ...string[]]>, {
|
|
188
|
+
name: string;
|
|
189
|
+
tableName: "latest_observations";
|
|
190
|
+
dataType: "string";
|
|
191
|
+
data: string;
|
|
192
|
+
driverParam: string;
|
|
193
|
+
notNull: false;
|
|
194
|
+
hasDefault: false;
|
|
195
|
+
isPrimaryKey: false;
|
|
196
|
+
isAutoincrement: false;
|
|
197
|
+
hasRuntimeDefault: false;
|
|
198
|
+
enumValues: undefined;
|
|
199
|
+
identity: undefined;
|
|
200
|
+
generated: undefined;
|
|
201
|
+
}>;
|
|
202
|
+
};
|
|
203
|
+
dialect: "pg";
|
|
199
204
|
}>;
|
|
200
205
|
//# sourceMappingURL=schema.d.ts.map
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAoBA;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAexB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU7B,CAAC"}
|
package/dist/schema.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { boolean, index, integer,
|
|
1
|
+
import { boolean, index, integer, pgTable, text, timestamp, uuid, } from 'drizzle-orm/pg-core';
|
|
2
2
|
import { sql } from 'drizzle-orm';
|
|
3
3
|
const columns = {
|
|
4
4
|
id: uuid('id').notNull(),
|
|
@@ -21,16 +21,20 @@ export const observations = pgTable('observations', {
|
|
|
21
21
|
index('observations_monitor_observed_at_idx').on(table.monitor, sql `${table.observedAt} DESC`),
|
|
22
22
|
]);
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
24
|
+
* Latest observation per monitor, keyed by `monitor`. Kept current by an upsert
|
|
25
|
+
* on every write (see `PostgresObservationStore.store`) rather than a
|
|
26
|
+
* materialized view: reads are always current, and there is no periodic
|
|
27
|
+
* full-table `REFRESH` to fall behind, contend on locks, or scan the whole
|
|
28
|
+
* `observations` history every cycle.
|
|
25
29
|
*/
|
|
26
|
-
export const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
export const latestObservations = pgTable('latest_observations', {
|
|
31
|
+
// Fresh column builders (not the shared `columns`): drizzle binds a builder
|
|
32
|
+
// instance to one table, so reusing `columns` across two tables would drop
|
|
33
|
+
// this primary key — which `store`'s upsert relies on for ON CONFLICT.
|
|
34
|
+
id: uuid('id').notNull(),
|
|
35
|
+
monitor: text('monitor').primaryKey(),
|
|
36
|
+
observedAt: timestamp('observed_at', { mode: 'date' }).notNull(),
|
|
37
|
+
success: boolean('success').notNull(),
|
|
38
|
+
responseTimeMs: integer('response_time_ms').notNull(),
|
|
39
|
+
errorMessage: text('error_message'),
|
|
40
|
+
});
|
package/dist/service.d.ts
CHANGED
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EAEL,KAAK,eAAe,EAErB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE/E;;;GAGG;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC;AAEjC,MAAM,WAAW,qBAAqB;IACpC,yCAAyC;IACzC,KAAK,EAAE,gBAAgB,CAAC;IACxB,8BAA8B;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAID;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAU;IACnC,OAAO,CAAC,GAAG,CAAwB;gBAEvB,OAAO,EAAE,qBAAqB;IAU1C;;OAEG;IACG,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EAEL,KAAK,eAAe,EAErB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE/E;;;GAGG;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC;AAEjC,MAAM,WAAW,qBAAqB;IACpC,yCAAyC;IACzC,KAAK,EAAE,gBAAgB,CAAC;IACxB,8BAA8B;IAC9B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAID;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAU;IACnC,OAAO,CAAC,GAAG,CAAwB;gBAEvB,OAAO,EAAE,qBAAqB;IAU1C;;OAEG;IACG,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B;;OAEG;IACH,KAAK,IAAI,IAAI;IAQb;;OAEG;IACH,IAAI,IAAI,IAAI;IAOZ;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,OAAO,CAAC,aAAa;YAYP,YAAY;CAW3B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,IAAI,GACf,WAAW,CA+Bb"}
|
package/dist/service.js
CHANGED
|
@@ -31,14 +31,12 @@ export class MonitorService {
|
|
|
31
31
|
throw new Error(`Monitor not found: ${identifier}`);
|
|
32
32
|
}
|
|
33
33
|
await this.performCheck(config);
|
|
34
|
-
await this.refreshView();
|
|
35
34
|
}
|
|
36
35
|
/**
|
|
37
36
|
* Perform an immediate check for all monitors.
|
|
38
37
|
*/
|
|
39
38
|
async checkAll() {
|
|
40
39
|
await Promise.all(this.configs.map((config) => this.performCheck(config)));
|
|
41
|
-
await this.refreshView();
|
|
42
40
|
}
|
|
43
41
|
/**
|
|
44
42
|
* Start monitoring all configured distributions.
|
|
@@ -92,14 +90,6 @@ export class MonitorService {
|
|
|
92
90
|
const checkResult = mapProbeResult(result, observedAt);
|
|
93
91
|
await this.store.store({ monitor: config.identifier, ...checkResult });
|
|
94
92
|
}
|
|
95
|
-
async refreshView() {
|
|
96
|
-
try {
|
|
97
|
-
await this.store.refreshLatestObservationsView();
|
|
98
|
-
}
|
|
99
|
-
catch {
|
|
100
|
-
// View refresh failure is not critical
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
93
|
}
|
|
104
94
|
/**
|
|
105
95
|
* Collapse a {@link ProbeResultType} into a {@link CheckResult}. Network
|
package/dist/store.d.ts
CHANGED
|
@@ -22,6 +22,5 @@ export declare class PostgresObservationStore implements ObservationStore {
|
|
|
22
22
|
getLatest(): Promise<Map<string, Observation>>;
|
|
23
23
|
get(id: string): Promise<Observation | null>;
|
|
24
24
|
store(observation: Omit<Observation, 'id'>): Promise<Observation>;
|
|
25
|
-
refreshLatestObservationsView(): Promise<void>;
|
|
26
25
|
}
|
|
27
26
|
//# sourceMappingURL=store.d.ts.map
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAchE;;GAEG;AACH,qBAAa,wBAAyB,YAAW,gBAAgB;IAC/D,OAAO,CAAC,EAAE,CAAqB;IAE/B,OAAO;IAYP;;;;;;;;;;;OAWG;WACU,MAAM,CACjB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,wBAAwB,CAAC;IAqD9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAK9C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAS5C,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;CA4BxE"}
|
package/dist/store.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { drizzle } from 'drizzle-orm/postgres-js';
|
|
2
2
|
import { eq, sql } from 'drizzle-orm';
|
|
3
3
|
import * as schema from './schema.js';
|
|
4
|
-
const { observations, latestObservations
|
|
4
|
+
const { observations, latestObservations } = schema;
|
|
5
5
|
/**
|
|
6
|
-
* Per-session Postgres timeouts applied to every pooled connection
|
|
7
|
-
* that
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `statement_timeout` is a generous backstop against a single runaway query.
|
|
6
|
+
* Per-session Postgres timeouts applied to every pooled connection, so a
|
|
7
|
+
* statement that blocks on a lock or runs away fails fast rather than hanging
|
|
8
|
+
* indefinitely (which once stalled startup for hours). `lock_timeout` bounds
|
|
9
|
+
* lock waits; `statement_timeout` is a generous backstop against a single
|
|
10
|
+
* runaway query.
|
|
12
11
|
*/
|
|
13
12
|
const LOCK_TIMEOUT_MS = 30_000;
|
|
14
13
|
const STATEMENT_TIMEOUT_MS = 60_000;
|
|
@@ -42,6 +41,21 @@ export class PostgresObservationStore {
|
|
|
42
41
|
*/
|
|
43
42
|
static async create(connectionString) {
|
|
44
43
|
const store = new PostgresObservationStore(connectionString);
|
|
44
|
+
// Migrate away from the former `latest_observations` MATERIALIZED VIEW: it
|
|
45
|
+
// was a derived cache (every value also lives in `observations`), so dropping
|
|
46
|
+
// it loses nothing. Done before pushSchema so the declarative push can create
|
|
47
|
+
// the replacement table without tripping the destructive-change guard below.
|
|
48
|
+
// Guarded on pg_matviews, so it is a no-op once the table has taken over.
|
|
49
|
+
await store.db.execute(sql `
|
|
50
|
+
DO $$
|
|
51
|
+
BEGIN
|
|
52
|
+
IF EXISTS (
|
|
53
|
+
SELECT 1 FROM pg_matviews WHERE matviewname = 'latest_observations'
|
|
54
|
+
) THEN
|
|
55
|
+
DROP MATERIALIZED VIEW latest_observations;
|
|
56
|
+
END IF;
|
|
57
|
+
END $$;
|
|
58
|
+
`);
|
|
45
59
|
const { pushSchema } = await import('drizzle-kit/api-postgres');
|
|
46
60
|
// #5293 shim: drizzle-kit reads `.rows` off the execute() result, which the
|
|
47
61
|
// postgres-js driver returns as a bare array. Wrap it back into `{ rows }`.
|
|
@@ -62,12 +76,6 @@ export class PostgresObservationStore {
|
|
|
62
76
|
for (const statement of sqlStatements) {
|
|
63
77
|
await store.db.execute(sql.raw(statement));
|
|
64
78
|
}
|
|
65
|
-
// The unique index on the materialized view is required for
|
|
66
|
-
// REFRESH ... CONCURRENTLY but is not modelled by drizzle's
|
|
67
|
-
// `pgMaterializedView`, so `pushSchema` never emits it. Create it
|
|
68
|
-
// idempotently — `IF NOT EXISTS` matches by name and skips (no rebuild) when
|
|
69
|
-
// it already exists.
|
|
70
|
-
await store.db.execute(sql `CREATE UNIQUE INDEX IF NOT EXISTS latest_observations_monitor_idx ON latest_observations (monitor)`);
|
|
71
79
|
return store;
|
|
72
80
|
}
|
|
73
81
|
async close() {
|
|
@@ -87,13 +95,29 @@ export class PostgresObservationStore {
|
|
|
87
95
|
return rows[0] ?? null;
|
|
88
96
|
}
|
|
89
97
|
async store(observation) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
return this.db.transaction(async (tx) => {
|
|
99
|
+
const [inserted] = await tx
|
|
100
|
+
.insert(observations)
|
|
101
|
+
.values(observation)
|
|
102
|
+
.returning();
|
|
103
|
+
// Keep the latest-per-monitor row current in the same transaction. The
|
|
104
|
+
// `setWhere` guard skips the update when a newer observation is already
|
|
105
|
+
// recorded, so an out-of-order write can never move `latest` backwards.
|
|
106
|
+
await tx
|
|
107
|
+
.insert(latestObservations)
|
|
108
|
+
.values(inserted)
|
|
109
|
+
.onConflictDoUpdate({
|
|
110
|
+
target: latestObservations.monitor,
|
|
111
|
+
set: {
|
|
112
|
+
id: inserted.id,
|
|
113
|
+
observedAt: inserted.observedAt,
|
|
114
|
+
success: inserted.success,
|
|
115
|
+
responseTimeMs: inserted.responseTimeMs,
|
|
116
|
+
errorMessage: inserted.errorMessage,
|
|
117
|
+
},
|
|
118
|
+
setWhere: sql `${latestObservations.observedAt} <= excluded.observed_at`,
|
|
119
|
+
});
|
|
120
|
+
return inserted;
|
|
121
|
+
});
|
|
98
122
|
}
|
|
99
123
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -56,13 +56,9 @@ export interface ObservationStore {
|
|
|
56
56
|
*/
|
|
57
57
|
get(id: string): Promise<Observation | null>;
|
|
58
58
|
/**
|
|
59
|
-
* Save a new observation.
|
|
59
|
+
* Save a new observation. Also updates the latest-per-monitor record.
|
|
60
60
|
*/
|
|
61
61
|
store(observation: Omit<Observation, 'id'>): Promise<Observation>;
|
|
62
|
-
/**
|
|
63
|
-
* Refresh the latest_observations materialized view.
|
|
64
|
-
*/
|
|
65
|
-
refreshLatestObservationsView(): Promise<void>;
|
|
66
62
|
/**
|
|
67
63
|
* Close the database connection.
|
|
68
64
|
*/
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,YAAY,EAAE,YAAY,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,OAAO,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,sDAAsD;IACtD,UAAU,EAAE,IAAI,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAE/C;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE7C;;OAEG;IACH,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAElE;;OAEG;IACH,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,YAAY,EAAE,YAAY,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,OAAO,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,sDAAsD;IACtD,UAAU,EAAE,IAAI,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAE/C;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE7C;;OAEG;IACH,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAElE;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
|
package/package.json
CHANGED