signalk-questdb 1.5.0 → 1.5.2
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/README.md +11 -2
- package/dist/delta-routing.d.ts +2 -0
- package/dist/delta-routing.js +19 -0
- package/dist/delta-routing.js.map +1 -0
- package/dist/ilp-writer.d.ts +6 -4
- package/dist/ilp-writer.js +37 -4
- package/dist/ilp-writer.js.map +1 -1
- package/dist/index.js +157 -36
- package/dist/index.js.map +1 -1
- package/dist/questdb-endpoint.d.ts +37 -5
- package/dist/questdb-endpoint.js +90 -7
- package/dist/questdb-endpoint.js.map +1 -1
- package/dist/test/delta-routing.test.d.ts +1 -0
- package/dist/test/delta-routing.test.js +54 -0
- package/dist/test/delta-routing.test.js.map +1 -0
- package/dist/test/ilp-writer.test.js +86 -1
- package/dist/test/ilp-writer.test.js.map +1 -1
- package/dist/test/questdb-endpoint.test.js +151 -10
- package/dist/test/questdb-endpoint.test.js.map +1 -1
- package/doc/web-console.md +267 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,6 +49,13 @@ Three tables, all with WAL mode, daily partitioning, and deduplication:
|
|
|
49
49
|
| `signalk_str` | String values | `ts`, `path` (SYMBOL), `context` (SYMBOL), `value_str` (VARCHAR) |
|
|
50
50
|
| `signalk_position` | Positions | `ts`, `context` (SYMBOL), `lat` (DOUBLE), `lon` (DOUBLE) |
|
|
51
51
|
|
|
52
|
+
`ts` is the **server receive time**, not the timestamp a source claims. Marine
|
|
53
|
+
sources carry independent clocks, and storing their timestamps makes commits
|
|
54
|
+
land out of order — QuestDB then rewrites partition tails on every merge
|
|
55
|
+
(observed as >3000x write amplification). Receive time keeps ingestion
|
|
56
|
+
append-only; the millisecond difference is far below the sampling resolution,
|
|
57
|
+
and a device with a broken clock gets more accurate history, not less.
|
|
58
|
+
|
|
52
59
|
## History API
|
|
53
60
|
|
|
54
61
|
### v2 (REST -- `/signalk/v2/api/history/`)
|
|
@@ -153,8 +160,10 @@ QuestDB you point it at via `QuestDB host` + the HTTP/ILP ports.
|
|
|
153
160
|
|
|
154
161
|
## QuestDB Web Console
|
|
155
162
|
|
|
156
|
-
QuestDB ships a web console (SQL editor + import UI) on its HTTP port.
|
|
157
|
-
|
|
163
|
+
QuestDB ships a web console (SQL editor + import UI) on its HTTP port. See the
|
|
164
|
+
**[Web Console user guide](doc/web-console.md)** for an end-user walkthrough
|
|
165
|
+
with ready-to-paste sample queries (speed in knots, temperatures in °C,
|
|
166
|
+
distance per day, track export, and more). On the Signal K host it is at:
|
|
158
167
|
|
|
159
168
|
```
|
|
160
169
|
http://localhost:9000
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.routeDeltaValue = routeDeltaValue;
|
|
4
|
+
function routeDeltaValue(path, value) {
|
|
5
|
+
if (typeof value === "number")
|
|
6
|
+
return "number";
|
|
7
|
+
if (typeof value === "string")
|
|
8
|
+
return "string";
|
|
9
|
+
if (path === "navigation.position" &&
|
|
10
|
+
value !== null &&
|
|
11
|
+
typeof value === "object" &&
|
|
12
|
+
"latitude" in value &&
|
|
13
|
+
"longitude" in value &&
|
|
14
|
+
Number.isFinite(value.latitude) &&
|
|
15
|
+
Number.isFinite(value.longitude))
|
|
16
|
+
return "position";
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=delta-routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta-routing.js","sourceRoot":"","sources":["../src/delta-routing.ts"],"names":[],"mappings":";;AAUA,0CAcC;AAdD,SAAgB,eAAe,CAAC,IAAY,EAAE,KAAc;IAC1D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/C,IACE,IAAI,KAAK,qBAAqB;QAC9B,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;QACzB,UAAU,IAAI,KAAK;QACnB,WAAW,IAAI,KAAK;QACpB,MAAM,CAAC,QAAQ,CAAE,KAA+B,CAAC,QAAQ,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAE,KAAgC,CAAC,SAAS,CAAC;QAE5D,OAAO,UAAU,CAAC;IACpB,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/ilp-writer.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare class ILPWriter {
|
|
|
11
11
|
private connected;
|
|
12
12
|
private connecting;
|
|
13
13
|
private stopped;
|
|
14
|
+
private lastNanos;
|
|
14
15
|
private connectedAt;
|
|
15
16
|
private consecutiveFlaps;
|
|
16
17
|
private droppedLines;
|
|
@@ -40,12 +41,13 @@ export declare class ILPWriter {
|
|
|
40
41
|
private markUnhealthy;
|
|
41
42
|
private markHealthy;
|
|
42
43
|
private scheduleReconnect;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
private nextNanos;
|
|
45
|
+
write(path: string, context: string, value: number, timestamp?: Date): void;
|
|
46
|
+
writeString(path: string, context: string, value: string, timestamp?: Date): void;
|
|
47
|
+
writePosition(context: string, position: {
|
|
46
48
|
latitude: number;
|
|
47
49
|
longitude: number;
|
|
48
|
-
}, timestamp
|
|
50
|
+
}, timestamp?: Date): void;
|
|
49
51
|
private enqueue;
|
|
50
52
|
private requeueFront;
|
|
51
53
|
private enforceBufferCap;
|
package/dist/ilp-writer.js
CHANGED
|
@@ -85,6 +85,17 @@ class ILPWriter {
|
|
|
85
85
|
connected = false;
|
|
86
86
|
connecting = false;
|
|
87
87
|
stopped = false;
|
|
88
|
+
// Last timestamp handed out, in nanoseconds. Rows are stamped at write time
|
|
89
|
+
// with the server clock (see the delta handler), but `Date` is only
|
|
90
|
+
// millisecond-resolution while the `signalk`/`signalk_str` tables dedup on
|
|
91
|
+
// KEYS(ts, path, context). Two writes for the same path within one
|
|
92
|
+
// millisecond would collide and the later would upsert over the earlier —
|
|
93
|
+
// silent data loss for unthrottled (samplingRate 0) or bursty paths. QuestDB
|
|
94
|
+
// stores microsecond resolution, so advancing this counter by at least 1µs
|
|
95
|
+
// per write keeps every row's `ts` distinct without moving the visible
|
|
96
|
+
// millisecond. It only ratchets forward: a same/earlier wall-clock reading
|
|
97
|
+
// is bumped past the last one, so ingestion also stays strictly ordered.
|
|
98
|
+
lastNanos = 0n;
|
|
88
99
|
// Wall-clock ms when the current socket's connect callback fired. Read in the
|
|
89
100
|
// `close` handler to decide whether the connection was stable (reset backoff)
|
|
90
101
|
// or an instant flap (grow backoff). Reset to 0 on every close.
|
|
@@ -246,16 +257,38 @@ class ILPWriter {
|
|
|
246
257
|
});
|
|
247
258
|
}, this.reconnectDelay);
|
|
248
259
|
}
|
|
260
|
+
// Strictly-increasing nanosecond timestamp for the next row. Starts from the
|
|
261
|
+
// server clock but never repeats or goes backwards within one writer, so
|
|
262
|
+
// same-millisecond writes to a dedup table don't collide (see `lastNanos`).
|
|
263
|
+
// An explicit `Date` (used by tests that assert exact ILP lines) is honoured
|
|
264
|
+
// verbatim, but still advances the floor so it can't collide with a later
|
|
265
|
+
// omitted-timestamp write.
|
|
266
|
+
nextNanos(explicit) {
|
|
267
|
+
if (explicit) {
|
|
268
|
+
const explicitNanos = BigInt(explicit.getTime()) * 1000000n;
|
|
269
|
+
if (explicitNanos > this.lastNanos)
|
|
270
|
+
this.lastNanos = explicitNanos;
|
|
271
|
+
return explicitNanos;
|
|
272
|
+
}
|
|
273
|
+
const nowNanos = BigInt(Date.now()) * 1000000n;
|
|
274
|
+
// Advance by at least 1µs (QuestDB's storage resolution) past the last
|
|
275
|
+
// value so the microsecond QuestDB persists is always distinct.
|
|
276
|
+
this.lastNanos =
|
|
277
|
+
nowNanos > this.lastNanos ? nowNanos : this.lastNanos + 1000n;
|
|
278
|
+
return this.lastNanos;
|
|
279
|
+
}
|
|
249
280
|
write(path, context, value, timestamp) {
|
|
250
|
-
const ts =
|
|
281
|
+
const ts = this.nextNanos(timestamp);
|
|
251
282
|
this.enqueue(`signalk,path=${escapeTag(path)},context=${escapeTag(context)} value=${value} ${ts}\n`);
|
|
252
283
|
}
|
|
253
284
|
writeString(path, context, value, timestamp) {
|
|
254
|
-
const ts =
|
|
285
|
+
const ts = this.nextNanos(timestamp);
|
|
255
286
|
this.enqueue(`signalk_str,path=${escapeTag(path)},context=${escapeTag(context)} value_str="${escapeFieldString(value)}" ${ts}\n`);
|
|
256
287
|
}
|
|
257
|
-
|
|
258
|
-
|
|
288
|
+
// signalk_position has no path column — it holds navigation.position rows
|
|
289
|
+
// exclusively (the caller enforces that), keyed on ts+context.
|
|
290
|
+
writePosition(context, position, timestamp) {
|
|
291
|
+
const ts = this.nextNanos(timestamp);
|
|
259
292
|
this.enqueue(`signalk_position,context=${escapeTag(context)} lat=${position.latitude},lon=${position.longitude} ${ts}\n`);
|
|
260
293
|
}
|
|
261
294
|
enqueue(line) {
|
package/dist/ilp-writer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ilp-writer.js","sourceRoot":"","sources":["../src/ilp-writer.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ilp-writer.js","sourceRoot":"","sources":["../src/ilp-writer.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ const minimatch_1 = require("minimatch");
|
|
|
37
37
|
const ilp_writer_1 = require("./ilp-writer");
|
|
38
38
|
const query_client_1 = require("./query-client");
|
|
39
39
|
const schema_1 = require("./config/schema");
|
|
40
|
+
const delta_routing_1 = require("./delta-routing");
|
|
40
41
|
const history_v2_1 = require("./history-v2");
|
|
41
42
|
const history_v1_1 = require("./history-v1");
|
|
42
43
|
const retention_1 = require("./retention");
|
|
@@ -123,6 +124,20 @@ module.exports = (app) => {
|
|
|
123
124
|
// could resurrect a just-purged container. A simple promise-chain mutex:
|
|
124
125
|
// each call waits for the previous to settle, then runs.
|
|
125
126
|
let lifecycleChain = Promise.resolve();
|
|
127
|
+
// Bumped by stop() and purge before they tear down. Lifecycle work captures
|
|
128
|
+
// the value when it is ENQUEUED and re-checks it when it actually runs (and
|
|
129
|
+
// after its long awaits): startAbort can only cancel the start that is
|
|
130
|
+
// currently executing, so without this a start/update still waiting behind
|
|
131
|
+
// the chain — or one parked in a long await — would run to completion after
|
|
132
|
+
// teardown and resurrect the resources that were just torn down.
|
|
133
|
+
let lifecycleGeneration = 0;
|
|
134
|
+
// True only between a FULLY completed start (providers, stream
|
|
135
|
+
// subscription, and timers all registered) and the next stop/purge.
|
|
136
|
+
// queryClient/writer are not usable as a running sentinel: they are
|
|
137
|
+
// created partway through startup, so a start that fails after that point
|
|
138
|
+
// (health-wait exhausted, ensureTables/connect threw) leaves them non-null
|
|
139
|
+
// on a plugin that never came up.
|
|
140
|
+
let pluginRunning = false;
|
|
126
141
|
const withLifecycleLock = (fn) => {
|
|
127
142
|
const run = lifecycleChain.then(fn, fn);
|
|
128
143
|
// Keep the chain alive regardless of this op's outcome.
|
|
@@ -244,12 +259,15 @@ module.exports = (app) => {
|
|
|
244
259
|
* QuestDB is not published beyond loopback / the shared network.
|
|
245
260
|
* - on: publish the configured host ports on 0.0.0.0 (for LAN / separate-
|
|
246
261
|
* Docker Grafana) on the shared `networkName`; the Signal K process
|
|
247
|
-
* reaches them on the host loopback (bare-metal) or
|
|
248
|
-
* host.containers.internal
|
|
262
|
+
* reaches them on the host loopback (bare-metal) or — containerized —
|
|
263
|
+
* on whichever of loopback/host.containers.internal actually answers
|
|
264
|
+
* (probed, since the right one depends on the SK container's network
|
|
265
|
+
* mode; see resolveLanExposureHost).
|
|
249
266
|
*
|
|
250
|
-
* `endpoints` is resolved AFTER ensureRunning() on the
|
|
251
|
-
* path
|
|
252
|
-
*
|
|
267
|
+
* `endpoints` is resolved AFTER ensureRunning() on both paths: the
|
|
268
|
+
* signalkAccessiblePorts path needs the allocated host port, and the LAN
|
|
269
|
+
* path's probe needs a running QuestDB. The returned resolver defers the
|
|
270
|
+
* work into the closure (memoized on the LAN path) for exactly that reason.
|
|
253
271
|
*/
|
|
254
272
|
async function applyQuestdbNetworking(config, containers, name, containerConfig) {
|
|
255
273
|
const httpPort = config.questdbHttpPort ?? questdb_endpoint_1.QUESTDB_INTERNAL_HTTP_PORT;
|
|
@@ -274,14 +292,22 @@ module.exports = (app) => {
|
|
|
274
292
|
await containers.ensureNetwork(config.networkName);
|
|
275
293
|
containerConfig.networkMode = config.networkName;
|
|
276
294
|
}
|
|
277
|
-
// A 0.0.0.0-published port is
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
return async () =>
|
|
295
|
+
// A 0.0.0.0-published port is reached on 127.0.0.1 or via the host
|
|
296
|
+
// gateway depending on how a containerized SK is networked — resolved
|
|
297
|
+
// by probing, which only works once QuestDB is up. The resolver runs
|
|
298
|
+
// after ensureRunning() on both call sites, so defer the probe into
|
|
299
|
+
// the closure (and memoize: the endpoint can't change while the
|
|
300
|
+
// container config that produced it is live).
|
|
301
|
+
let endpoints = null;
|
|
302
|
+
return async () => {
|
|
303
|
+
if (!endpoints) {
|
|
304
|
+
const skHost = config.exposeToContainers
|
|
305
|
+
? await (0, questdb_endpoint_1.resolveLanExposureHost)(containers, httpPort, (msg) => app.debug(msg))
|
|
306
|
+
: "127.0.0.1";
|
|
307
|
+
endpoints = (0, questdb_endpoint_1.lanExposureEndpoints)(skHost, httpPort, ilpPort);
|
|
308
|
+
}
|
|
309
|
+
return endpoints;
|
|
310
|
+
};
|
|
285
311
|
}
|
|
286
312
|
// Default path: signalk-container owns the networking. After the container
|
|
287
313
|
// is up we additionally attach it to `networkName` so the companion
|
|
@@ -359,6 +385,9 @@ module.exports = (app) => {
|
|
|
359
385
|
}
|
|
360
386
|
}
|
|
361
387
|
async function runStartInner(config, signal) {
|
|
388
|
+
// Not running until THIS start completes — a restart that reuses the
|
|
389
|
+
// slot must not leave a stale true from the previous run.
|
|
390
|
+
pluginRunning = false;
|
|
362
391
|
// Older saved configs miss keys added since (pathFilter, samplingRates);
|
|
363
392
|
// the per-delta pipeline dereferences them per delta, so normalize once
|
|
364
393
|
// at the boundary.
|
|
@@ -463,7 +492,13 @@ module.exports = (app) => {
|
|
|
463
492
|
if (signal.aborted)
|
|
464
493
|
return;
|
|
465
494
|
app.debug("QuestDB container ready");
|
|
466
|
-
|
|
495
|
+
// The LAN path probes for the reachable host in here (up to its
|
|
496
|
+
// retry deadline), so this await is long enough for a stop/purge to
|
|
497
|
+
// preempt us — re-check before committing the result.
|
|
498
|
+
const resolved = await resolveEndpoints();
|
|
499
|
+
if (signal.aborted)
|
|
500
|
+
return;
|
|
501
|
+
questdbEndpoints = resolved;
|
|
467
502
|
}
|
|
468
503
|
catch (err) {
|
|
469
504
|
app.debug("ensureRunning failed:", err);
|
|
@@ -542,7 +577,7 @@ module.exports = (app) => {
|
|
|
542
577
|
const unsub = bus.onValue((delta) => {
|
|
543
578
|
if (!writer)
|
|
544
579
|
return;
|
|
545
|
-
const { path, value, context
|
|
580
|
+
const { path, value, context } = delta;
|
|
546
581
|
if (!path || value === undefined || value === null)
|
|
547
582
|
return;
|
|
548
583
|
const isSelf = context === app.selfContext;
|
|
@@ -554,19 +589,28 @@ module.exports = (app) => {
|
|
|
554
589
|
return;
|
|
555
590
|
if (isThrottled(path, config.samplingRates, config.defaultSamplingRate ?? 2000))
|
|
556
591
|
return;
|
|
557
|
-
|
|
592
|
+
// Rows are stamped with the server receive time, deliberately NOT the
|
|
593
|
+
// delta's own timestamp: a boat is a set of independent clocks (GPS
|
|
594
|
+
// time, RTC-less devices, gateway latencies), and storing per-source
|
|
595
|
+
// timestamps makes commits land out of order. QuestDB then rewrites
|
|
596
|
+
// partition tails on every merge — observed in the field as >3000x
|
|
597
|
+
// write amplification (physical rows rewritten per row inserted),
|
|
598
|
+
// grinding SD cards and, before batching, stalling the WAL outright.
|
|
599
|
+
// The writer assigns the actual timestamp (strictly monotonic to the
|
|
600
|
+
// microsecond, so same-millisecond writes don't collide on the dedup
|
|
601
|
+
// key), so every commit is a pure append. A device with a broken clock
|
|
602
|
+
// even gets *more* accurate history. Re-sent ILP batches keep their
|
|
603
|
+
// original stamps (baked at write() time), so replay-idempotency holds.
|
|
558
604
|
const ctx = isSelf ? "self" : context;
|
|
559
|
-
|
|
560
|
-
|
|
605
|
+
const route = (0, delta_routing_1.routeDeltaValue)(path, value);
|
|
606
|
+
if (route === "number") {
|
|
607
|
+
writer.write(path, ctx, value);
|
|
561
608
|
}
|
|
562
|
-
else if (
|
|
563
|
-
writer.writeString(path, ctx, value
|
|
609
|
+
else if (route === "string") {
|
|
610
|
+
writer.writeString(path, ctx, value);
|
|
564
611
|
}
|
|
565
|
-
else if (
|
|
566
|
-
|
|
567
|
-
"latitude" in value &&
|
|
568
|
-
"longitude" in value) {
|
|
569
|
-
writer.writePosition(path, ctx, value, ts);
|
|
612
|
+
else if (route === "position") {
|
|
613
|
+
writer.writePosition(ctx, value);
|
|
570
614
|
}
|
|
571
615
|
});
|
|
572
616
|
unsubscribes.push(unsub);
|
|
@@ -580,11 +624,25 @@ module.exports = (app) => {
|
|
|
580
624
|
void healSchemaTables();
|
|
581
625
|
}, SCHEMA_HEAL_INTERVAL_MS);
|
|
582
626
|
app.setPluginStatus(`Recording to QuestDB at ${ilpHost}:${ilpPort}`);
|
|
627
|
+
// Everything is registered — only now does the plugin count as running.
|
|
628
|
+
// Any earlier return/throw leaves the flag false, so a half-started
|
|
629
|
+
// plugin rejects lifecycle-dependent requests like /api/update/apply.
|
|
630
|
+
pluginRunning = true;
|
|
583
631
|
}
|
|
584
632
|
// Public entry: serialize startup behind the lifecycle lock so a purge or
|
|
585
|
-
// update can't interleave with it.
|
|
633
|
+
// update can't interleave with it. The generation is captured at enqueue: a
|
|
634
|
+
// stop()/purge landing while this start is still queued invalidates it
|
|
635
|
+
// before it begins — the window startAbort cannot cover, since the abort
|
|
636
|
+
// controller only exists once runStart() is executing.
|
|
586
637
|
function asyncStart(config) {
|
|
587
|
-
|
|
638
|
+
const generation = lifecycleGeneration;
|
|
639
|
+
return withLifecycleLock(async () => {
|
|
640
|
+
if (generation !== lifecycleGeneration) {
|
|
641
|
+
app.debug("skipping queued start: plugin stopped while it waited");
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
await runStart(config);
|
|
645
|
+
});
|
|
588
646
|
}
|
|
589
647
|
const plugin = {
|
|
590
648
|
id: "signalk-questdb",
|
|
@@ -598,6 +656,15 @@ module.exports = (app) => {
|
|
|
598
656
|
});
|
|
599
657
|
},
|
|
600
658
|
async stop() {
|
|
659
|
+
// Preempt lifecycle work: bump the generation so anything still queued
|
|
660
|
+
// behind the lifecycle chain (or parked in a long await that re-checks
|
|
661
|
+
// it) bails, and abort the currently-executing start so its post-await
|
|
662
|
+
// signal checks return before registering resources. Together these
|
|
663
|
+
// keep a slow start/update (container pull, LAN-host probe) from
|
|
664
|
+
// resurrecting a writer/client after this teardown ran.
|
|
665
|
+
lifecycleGeneration++;
|
|
666
|
+
startAbort?.abort();
|
|
667
|
+
pluginRunning = false;
|
|
601
668
|
for (const unsub of unsubscribes) {
|
|
602
669
|
try {
|
|
603
670
|
unsub();
|
|
@@ -861,6 +928,10 @@ module.exports = (app) => {
|
|
|
861
928
|
});
|
|
862
929
|
router.post("/api/update/apply", async (_req, res) => {
|
|
863
930
|
try {
|
|
931
|
+
// Captured at route entry, before ANY await: a stop() that lands
|
|
932
|
+
// during the release fetch below must already invalidate this
|
|
933
|
+
// update, not just one that lands after the lock is acquired.
|
|
934
|
+
const updateGeneration = lifecycleGeneration;
|
|
864
935
|
const containers = globalThis.__signalk_containerManager;
|
|
865
936
|
if (!containers || !containers.getRuntime()) {
|
|
866
937
|
res.status(503).json({ error: "Container manager not available" });
|
|
@@ -884,9 +955,26 @@ module.exports = (app) => {
|
|
|
884
955
|
const newTag = stable.tag_name;
|
|
885
956
|
// Run the mutating update under the lifecycle lock so a concurrent
|
|
886
957
|
// purge/start can't interleave with the pull + recreate + reconnect.
|
|
958
|
+
// The route-entry generation is re-checked at lock entry and after
|
|
959
|
+
// the long awaits: a stop() during the release fetch, the pull, or
|
|
960
|
+
// the LAN-host probe must not let this resume, reassign endpoints,
|
|
961
|
+
// and report success for a container the teardown already dealt
|
|
962
|
+
// with.
|
|
887
963
|
const ilp = await withLifecycleLock(async () => {
|
|
964
|
+
const assertNotStopped = () => {
|
|
965
|
+
if (updateGeneration !== lifecycleGeneration)
|
|
966
|
+
throw new Error("plugin stopped while the update was running");
|
|
967
|
+
};
|
|
968
|
+
assertNotStopped();
|
|
969
|
+
// A generation match only proves no stop() happened since route
|
|
970
|
+
// entry — it can't tell that the plugin was already stopped (or
|
|
971
|
+
// never fully started) when the request arrived. Gate on the
|
|
972
|
+
// completed-start sentinel before pulling or recreating anything.
|
|
973
|
+
if (!pluginRunning)
|
|
974
|
+
throw new Error("plugin is not running");
|
|
888
975
|
app.setPluginStatus(`Pulling QuestDB ${newTag}...`);
|
|
889
976
|
await containers.pullImage(`questdb/questdb:${newTag}`);
|
|
977
|
+
assertNotStopped();
|
|
890
978
|
if (currentConfig) {
|
|
891
979
|
currentConfig.questdbVersion = newTag;
|
|
892
980
|
await new Promise((resolve, reject) => {
|
|
@@ -932,11 +1020,15 @@ module.exports = (app) => {
|
|
|
932
1020
|
};
|
|
933
1021
|
const resolveUpdateEndpoints = await applyQuestdbNetworking(currentConfig ?? {}, containers, QUESTDB_CONTAINER_NAME, updateConfig);
|
|
934
1022
|
// Clear any prior clamp before re-running so a no-longer-clamping
|
|
935
|
-
// update doesn't leave a stale warning.
|
|
1023
|
+
// update doesn't leave a stale warning. The recreate must not
|
|
1024
|
+
// happen after a stop/purge teardown, so gate it on the
|
|
1025
|
+
// generation one more time.
|
|
1026
|
+
assertNotStopped();
|
|
936
1027
|
ulimitClamp = null;
|
|
937
1028
|
await containers.ensureRunning(QUESTDB_CONTAINER_NAME, updateConfig, {
|
|
938
1029
|
onUlimitClamped,
|
|
939
1030
|
});
|
|
1031
|
+
assertNotStopped();
|
|
940
1032
|
// The QuestDB version just changed, so the cached wal_tables()
|
|
941
1033
|
// column shape may no longer match (the errorTag/errorMessage
|
|
942
1034
|
// columns could appear on an upgrade or disappear on a downgrade).
|
|
@@ -947,26 +1039,51 @@ module.exports = (app) => {
|
|
|
947
1039
|
// current endpoint. The version bump keeps the same container name
|
|
948
1040
|
// and networking, so the endpoint is stable — the existing
|
|
949
1041
|
// QueryClient/ILPWriter stay valid (and the registered history
|
|
950
|
-
// providers keep their reference).
|
|
951
|
-
|
|
1042
|
+
// providers keep their reference). On the LAN path this await
|
|
1043
|
+
// probes for the reachable host, so it's long enough for a stop()
|
|
1044
|
+
// to land mid-flight — re-check before touching plugin state.
|
|
1045
|
+
const updatedEndpoints = await resolveUpdateEndpoints();
|
|
1046
|
+
assertNotStopped();
|
|
1047
|
+
questdbEndpoints = updatedEndpoints;
|
|
952
1048
|
const { host: ilpHost, port: ilpPort } = questdbEndpoints.ilp;
|
|
953
1049
|
// Wait for the recreated container to answer, then reconnect ILP.
|
|
954
|
-
|
|
1050
|
+
// Locals are captured because stop() nulls the module bindings:
|
|
1051
|
+
// reading them again mid-loop would throw, and the generation
|
|
1052
|
+
// checks after every await are what keep a concurrent teardown
|
|
1053
|
+
// from being resurrected by the reconnect.
|
|
1054
|
+
const client = queryClient;
|
|
1055
|
+
if (client) {
|
|
955
1056
|
const deadline = Date.now() + 30000;
|
|
956
1057
|
while (Date.now() < deadline) {
|
|
957
|
-
|
|
1058
|
+
assertNotStopped();
|
|
1059
|
+
if (await client.isHealthy())
|
|
958
1060
|
break;
|
|
959
1061
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
960
1062
|
}
|
|
961
1063
|
}
|
|
962
|
-
|
|
1064
|
+
assertNotStopped();
|
|
1065
|
+
const ilpWriter = writer;
|
|
1066
|
+
if (ilpWriter) {
|
|
963
1067
|
try {
|
|
964
|
-
await
|
|
1068
|
+
await ilpWriter.disconnect();
|
|
965
1069
|
}
|
|
966
1070
|
catch {
|
|
967
1071
|
/* ignore */
|
|
968
1072
|
}
|
|
969
|
-
|
|
1073
|
+
assertNotStopped();
|
|
1074
|
+
await ilpWriter.connect();
|
|
1075
|
+
// A stop() that landed during connect() has already nulled
|
|
1076
|
+
// `writer`, so nothing would ever disconnect this fresh
|
|
1077
|
+
// connection — close it ourselves before failing the update.
|
|
1078
|
+
if (updateGeneration !== lifecycleGeneration) {
|
|
1079
|
+
try {
|
|
1080
|
+
await ilpWriter.disconnect();
|
|
1081
|
+
}
|
|
1082
|
+
catch {
|
|
1083
|
+
/* ignore */
|
|
1084
|
+
}
|
|
1085
|
+
assertNotStopped();
|
|
1086
|
+
}
|
|
970
1087
|
}
|
|
971
1088
|
return { ilpHost, ilpPort };
|
|
972
1089
|
});
|
|
@@ -1087,6 +1204,7 @@ module.exports = (app) => {
|
|
|
1087
1204
|
if (teardownStarted)
|
|
1088
1205
|
return;
|
|
1089
1206
|
teardownStarted = true;
|
|
1207
|
+
pluginRunning = false;
|
|
1090
1208
|
// Stop all activity against the container before it and its data go
|
|
1091
1209
|
// away — otherwise the retention timer keeps issuing DROP PARTITION
|
|
1092
1210
|
// against a removed container and the writer keeps trying to connect.
|
|
@@ -1115,13 +1233,16 @@ module.exports = (app) => {
|
|
|
1115
1233
|
// Purge is the RECOVERY action, so it must make progress even when a
|
|
1116
1234
|
// start is wedged on a never-settling container call. Step 1: signal
|
|
1117
1235
|
// any in-flight start to bail (its post-await checks return without
|
|
1118
|
-
// creating resources)
|
|
1236
|
+
// creating resources) and bump the generation so a start/update
|
|
1237
|
+
// still QUEUED behind the chain bails at entry instead of running
|
|
1238
|
+
// after the teardown. Step 2: try to acquire the lifecycle lock so
|
|
1119
1239
|
// we still serialize against a start/update that IS progressing —
|
|
1120
1240
|
// but only for a bounded time. If the lock isn't free within
|
|
1121
1241
|
// PURGE_LOCK_TIMEOUT_MS (a truly hung start that ignored the abort
|
|
1122
1242
|
// and never released it), run the teardown anyway. Interleaving risk
|
|
1123
1243
|
// is minimal because we already aborted the start, so any start that
|
|
1124
1244
|
// later wakes up returns early instead of recreating the container.
|
|
1245
|
+
lifecycleGeneration++;
|
|
1125
1246
|
startAbort?.abort();
|
|
1126
1247
|
let lockedTeardownSettled = false;
|
|
1127
1248
|
let lockedTeardownError;
|