signalk-questdb 2.1.0 → 2.1.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/dist/ilp-writer.d.ts +1 -0
- package/dist/ilp-writer.js +17 -1
- package/dist/ilp-writer.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/migration.js +40 -45
- package/dist/migration.js.map +1 -1
- package/dist/wal-monitor.js +1 -1
- package/dist/wal-monitor.js.map +1 -1
- package/package.json +2 -2
- package/dist/test/config.test.d.ts +0 -1
- package/dist/test/config.test.js +0 -161
- package/dist/test/config.test.js.map +0 -1
- package/dist/test/configpanel-responses.test.d.ts +0 -1
- package/dist/test/configpanel-responses.test.js +0 -197
- package/dist/test/configpanel-responses.test.js.map +0 -1
- package/dist/test/console-proxy.test.d.ts +0 -1
- package/dist/test/console-proxy.test.js +0 -664
- package/dist/test/console-proxy.test.js.map +0 -1
- package/dist/test/container-env.test.d.ts +0 -1
- package/dist/test/container-env.test.js +0 -70
- package/dist/test/container-env.test.js.map +0 -1
- package/dist/test/delta-routing.test.d.ts +0 -1
- package/dist/test/delta-routing.test.js +0 -258
- package/dist/test/delta-routing.test.js.map +0 -1
- package/dist/test/full-export-range.test.d.ts +0 -1
- package/dist/test/full-export-range.test.js +0 -78
- package/dist/test/full-export-range.test.js.map +0 -1
- package/dist/test/history-v1.test.d.ts +0 -1
- package/dist/test/history-v1.test.js +0 -676
- package/dist/test/history-v1.test.js.map +0 -1
- package/dist/test/history-v2.test.d.ts +0 -1
- package/dist/test/history-v2.test.js +0 -1001
- package/dist/test/history-v2.test.js.map +0 -1
- package/dist/test/host-limits.test.d.ts +0 -1
- package/dist/test/host-limits.test.js +0 -81
- package/dist/test/host-limits.test.js.map +0 -1
- package/dist/test/ilp-writer.test.d.ts +0 -1
- package/dist/test/ilp-writer.test.js +0 -419
- package/dist/test/ilp-writer.test.js.map +0 -1
- package/dist/test/influx-detect.test.d.ts +0 -1
- package/dist/test/influx-detect.test.js +0 -287
- package/dist/test/influx-detect.test.js.map +0 -1
- package/dist/test/migration.test.d.ts +0 -1
- package/dist/test/migration.test.js +0 -851
- package/dist/test/migration.test.js.map +0 -1
- package/dist/test/package-e2e.test.d.ts +0 -1
- package/dist/test/package-e2e.test.js +0 -306
- package/dist/test/package-e2e.test.js.map +0 -1
- package/dist/test/path-matcher.test.d.ts +0 -1
- package/dist/test/path-matcher.test.js +0 -224
- package/dist/test/path-matcher.test.js.map +0 -1
- package/dist/test/query-client.test.d.ts +0 -1
- package/dist/test/query-client.test.js +0 -299
- package/dist/test/query-client.test.js.map +0 -1
- package/dist/test/questdb-endpoint.test.d.ts +0 -1
- package/dist/test/questdb-endpoint.test.js +0 -297
- package/dist/test/questdb-endpoint.test.js.map +0 -1
- package/dist/test/restore.test.d.ts +0 -1
- package/dist/test/restore.test.js +0 -543
- package/dist/test/restore.test.js.map +0 -1
- package/dist/test/time-range.test.d.ts +0 -1
- package/dist/test/time-range.test.js +0 -53
- package/dist/test/time-range.test.js.map +0 -1
- package/dist/test/wal-monitor.test.d.ts +0 -1
- package/dist/test/wal-monitor.test.js +0 -405
- package/dist/test/wal-monitor.test.js.map +0 -1
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { Temporal } from "@js-temporal/polyfill";
|
|
4
|
-
import { resolveTimeRange } from "../time-range.js";
|
|
5
|
-
describe("resolveTimeRange", () => {
|
|
6
|
-
it("resolves from + to", () => {
|
|
7
|
-
const from = Temporal.Instant.from("2024-01-01T00:00:00Z");
|
|
8
|
-
const to = Temporal.Instant.from("2024-01-02T00:00:00Z");
|
|
9
|
-
const result = resolveTimeRange({ from, to });
|
|
10
|
-
assert.ok(result.from.includes("2024-01-01"));
|
|
11
|
-
assert.ok(result.to.includes("2024-01-02"));
|
|
12
|
-
});
|
|
13
|
-
it("resolves from + duration", () => {
|
|
14
|
-
const from = Temporal.Instant.from("2024-01-01T00:00:00Z");
|
|
15
|
-
const duration = Temporal.Duration.from({ hours: 1 });
|
|
16
|
-
const result = resolveTimeRange({ from, duration });
|
|
17
|
-
assert.ok(result.from.includes("2024-01-01"));
|
|
18
|
-
assert.ok(result.to.includes("2024-01-01T01:00:00"));
|
|
19
|
-
});
|
|
20
|
-
it("resolves to + duration", () => {
|
|
21
|
-
const to = Temporal.Instant.from("2024-01-02T00:00:00Z");
|
|
22
|
-
const duration = Temporal.Duration.from({ hours: 1 });
|
|
23
|
-
const result = resolveTimeRange({ to, duration });
|
|
24
|
-
assert.ok(result.from.includes("2024-01-01T23:00:00"));
|
|
25
|
-
assert.ok(result.to.includes("2024-01-02"));
|
|
26
|
-
});
|
|
27
|
-
it("resolves from only (to defaults to now)", () => {
|
|
28
|
-
const from = Temporal.Instant.from("2024-01-01T00:00:00Z");
|
|
29
|
-
const result = resolveTimeRange({ from });
|
|
30
|
-
assert.ok(result.from.includes("2024-01-01"));
|
|
31
|
-
// to should be close to now
|
|
32
|
-
const toDate = new Date(result.to);
|
|
33
|
-
assert.ok(Date.now() - toDate.getTime() < 5000);
|
|
34
|
-
});
|
|
35
|
-
it("resolves duration only (from = now - duration)", () => {
|
|
36
|
-
const duration = Temporal.Duration.from({ minutes: 30 });
|
|
37
|
-
const result = resolveTimeRange({ duration });
|
|
38
|
-
const from = new Date(result.from);
|
|
39
|
-
const to = new Date(result.to);
|
|
40
|
-
const diffMs = to.getTime() - from.getTime();
|
|
41
|
-
// Should be approximately 30 minutes
|
|
42
|
-
assert.ok(Math.abs(diffMs - 30 * 60 * 1000) < 5000, `Expected ~30min diff, got ${diffMs}ms`);
|
|
43
|
-
});
|
|
44
|
-
it("resolves numeric duration (seconds)", () => {
|
|
45
|
-
const from = Temporal.Instant.from("2024-01-01T00:00:00Z");
|
|
46
|
-
const result = resolveTimeRange({ from, duration: 3600 });
|
|
47
|
-
assert.ok(result.to.includes("2024-01-01T01:00:00"));
|
|
48
|
-
});
|
|
49
|
-
it("throws on empty params", () => {
|
|
50
|
-
assert.throws(() => resolveTimeRange({}));
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
//# sourceMappingURL=time-range.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"time-range.test.js","sourceRoot":"","sources":["../../src/test/time-range.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,405 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { WalMonitor, buildPendingSegmentsSQL, computeSkipPlan, extractApplyError, isPartitionOpenFailure, skipPlansEqual, } from "../wal-monitor.js";
|
|
4
|
-
function segment(overrides = {}) {
|
|
5
|
-
return {
|
|
6
|
-
walId: 33,
|
|
7
|
-
segmentId: 20,
|
|
8
|
-
txns: 6,
|
|
9
|
-
minTxn: 4672112,
|
|
10
|
-
maxTxn: 4672117,
|
|
11
|
-
minTimestamp: "2026-07-01T04:22:14.701496Z",
|
|
12
|
-
maxTimestamp: "2026-07-01T04:22:17.204514Z",
|
|
13
|
-
...overrides,
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
function suspendedTable(overrides = {}) {
|
|
17
|
-
return {
|
|
18
|
-
name: "signalk_str",
|
|
19
|
-
writerTxn: 4672111,
|
|
20
|
-
sequencerTxn: 5456609,
|
|
21
|
-
txnLag: 784498,
|
|
22
|
-
errorTag: "",
|
|
23
|
-
errorMessage: "",
|
|
24
|
-
...overrides,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
describe("buildPendingSegmentsSQL", () => {
|
|
28
|
-
it("targets wal_transactions of the table with a strict txn lower bound", () => {
|
|
29
|
-
const sql = buildPendingSegmentsSQL("signalk_str", 4672111);
|
|
30
|
-
assert.match(sql, /FROM wal_transactions\('signalk_str'\)/);
|
|
31
|
-
assert.match(sql, /WHERE sequencerTxn > 4672111 /);
|
|
32
|
-
assert.match(sql, /GROUP BY walId, segmentId ORDER BY minTxn/);
|
|
33
|
-
});
|
|
34
|
-
it("escapes single quotes in the table name", () => {
|
|
35
|
-
const sql = buildPendingSegmentsSQL("bad'name", 1);
|
|
36
|
-
assert.match(sql, /wal_transactions\('bad''name'\)/);
|
|
37
|
-
});
|
|
38
|
-
it("floors and clamps the writer txn", () => {
|
|
39
|
-
assert.match(buildPendingSegmentsSQL("t", 12.9), /> 12 /);
|
|
40
|
-
assert.match(buildPendingSegmentsSQL("t", -5), /> 0 /);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
describe("computeSkipPlan", () => {
|
|
44
|
-
it("returns null when there are no pending segments", () => {
|
|
45
|
-
assert.equal(computeSkipPlan([]), null);
|
|
46
|
-
});
|
|
47
|
-
it("skips to the first txn of the next segment", () => {
|
|
48
|
-
const plan = computeSkipPlan([
|
|
49
|
-
segment(),
|
|
50
|
-
segment({
|
|
51
|
-
walId: 34,
|
|
52
|
-
segmentId: 0,
|
|
53
|
-
txns: 41499,
|
|
54
|
-
minTxn: 4672118,
|
|
55
|
-
maxTxn: 4713616,
|
|
56
|
-
minTimestamp: "2026-07-01T04:50:02.387389Z",
|
|
57
|
-
maxTimestamp: "2026-07-01T12:22:51.865153Z",
|
|
58
|
-
}),
|
|
59
|
-
]);
|
|
60
|
-
assert.ok(plan);
|
|
61
|
-
assert.equal(plan.skipToTxn, 4672118);
|
|
62
|
-
assert.equal(plan.skippedTxns, 6);
|
|
63
|
-
assert.equal(plan.skipWindowStart, "2026-07-01T04:22:14.701496Z");
|
|
64
|
-
assert.equal(plan.skipWindowEnd, "2026-07-01T04:22:17.204514Z");
|
|
65
|
-
assert.equal(plan.walId, 33);
|
|
66
|
-
assert.equal(plan.segmentId, 20);
|
|
67
|
-
assert.equal(plan.tailSkip, false);
|
|
68
|
-
});
|
|
69
|
-
it("flags a tail skip when the stuck segment is the newest", () => {
|
|
70
|
-
const plan = computeSkipPlan([segment()]);
|
|
71
|
-
assert.ok(plan);
|
|
72
|
-
assert.equal(plan.skipToTxn, 4672118);
|
|
73
|
-
assert.equal(plan.tailSkip, true);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
describe("skipPlansEqual", () => {
|
|
77
|
-
const plan = {
|
|
78
|
-
skipToTxn: 4672118,
|
|
79
|
-
skippedTxns: 6,
|
|
80
|
-
skipWindowStart: "2026-07-01T04:22:14.701496Z",
|
|
81
|
-
skipWindowEnd: "2026-07-01T04:22:17.204514Z",
|
|
82
|
-
walId: 33,
|
|
83
|
-
segmentId: 20,
|
|
84
|
-
tailSkip: false,
|
|
85
|
-
};
|
|
86
|
-
it("accepts an identical confirmation (including a JSON round-trip)", () => {
|
|
87
|
-
assert.equal(skipPlansEqual(plan, { ...plan }), true);
|
|
88
|
-
assert.equal(skipPlansEqual(plan, JSON.parse(JSON.stringify(plan))), true);
|
|
89
|
-
});
|
|
90
|
-
it("rejects non-object confirmations", () => {
|
|
91
|
-
assert.equal(skipPlansEqual(plan, undefined), false);
|
|
92
|
-
assert.equal(skipPlansEqual(plan, null), false);
|
|
93
|
-
assert.equal(skipPlansEqual(plan, 4672118), false);
|
|
94
|
-
});
|
|
95
|
-
it("rejects when any field diverges — same target txn is not enough", () => {
|
|
96
|
-
assert.equal(skipPlansEqual(plan, { ...plan, skippedTxns: 12000 }), false);
|
|
97
|
-
assert.equal(skipPlansEqual(plan, { ...plan, skipWindowEnd: "2026-07-05T00:00:00Z" }), false);
|
|
98
|
-
assert.equal(skipPlansEqual(plan, { ...plan, tailSkip: true }), false);
|
|
99
|
-
assert.equal(skipPlansEqual(plan, { ...plan, walId: 34 }), false);
|
|
100
|
-
assert.equal(skipPlansEqual(plan, { ...plan, segmentId: 21 }), false);
|
|
101
|
-
assert.equal(skipPlansEqual(plan, { ...plan, skipToTxn: 4672119 }), false);
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
describe("extractApplyError", () => {
|
|
105
|
-
const failure = [
|
|
106
|
-
"2026-07-17T22:22:51.774951Z C i.q.c.w.ApplyWal2TableJob job failed, table suspended [table=signalk_str~8, seqTxn=4672112, error=java.lang.AssertionError",
|
|
107
|
-
"\tat io.questdb.cairo.VarcharTypeDriver.getDataVectorSize(VarcharTypeDriver.java:175)",
|
|
108
|
-
"\tat io.questdb.cairo.TableWriter.processWalCommitBlock(TableWriter.java:9965)",
|
|
109
|
-
"]",
|
|
110
|
-
];
|
|
111
|
-
it("returns null when no failure is present", () => {
|
|
112
|
-
assert.equal(extractApplyError(["2026-07-17T22:22:51Z I job finished [table=x]"]), null);
|
|
113
|
-
});
|
|
114
|
-
it("captures the failure line and its stack up to the closing bracket", () => {
|
|
115
|
-
const lines = [
|
|
116
|
-
"2026-07-17T22:22:50Z I i.q.c.TableWriter open 'signalk_str~8'",
|
|
117
|
-
...failure,
|
|
118
|
-
"2026-07-17T22:22:56Z I i.q.c.w.ApplyWal2TableJob job finished [table=signalk~7]",
|
|
119
|
-
];
|
|
120
|
-
const error = extractApplyError(lines);
|
|
121
|
-
assert.ok(error);
|
|
122
|
-
assert.match(error, /job failed, table suspended/);
|
|
123
|
-
assert.match(error, /VarcharTypeDriver.getDataVectorSize/);
|
|
124
|
-
assert.ok(error.endsWith("]"));
|
|
125
|
-
assert.doesNotMatch(error, /job finished/);
|
|
126
|
-
});
|
|
127
|
-
it("uses the LAST failure when several are present", () => {
|
|
128
|
-
const older = failure.map((l) => l.replace("AssertionError", "OldError"));
|
|
129
|
-
const error = extractApplyError([...older, ...failure]);
|
|
130
|
-
assert.ok(error);
|
|
131
|
-
assert.match(error, /AssertionError/);
|
|
132
|
-
assert.doesNotMatch(error, /OldError/);
|
|
133
|
-
});
|
|
134
|
-
it("stops at the next timestamped entry when no bracket closes the stack", () => {
|
|
135
|
-
const error = extractApplyError([
|
|
136
|
-
failure[0],
|
|
137
|
-
failure[1],
|
|
138
|
-
"2026-07-17T22:22:52Z I unrelated next entry",
|
|
139
|
-
]);
|
|
140
|
-
assert.ok(error);
|
|
141
|
-
assert.doesNotMatch(error, /unrelated/);
|
|
142
|
-
});
|
|
143
|
-
it("scopes to the requested table when several tables have failures", () => {
|
|
144
|
-
const otherFailure = failure.map((l) => l
|
|
145
|
-
.replace("signalk_str~8", "signalk~7")
|
|
146
|
-
.replace("AssertionError", "OtherTableError"));
|
|
147
|
-
// The other table failed LAST — an unscoped scrape would return it.
|
|
148
|
-
const lines = [...failure, ...otherFailure];
|
|
149
|
-
const strError = extractApplyError(lines, "signalk_str");
|
|
150
|
-
assert.ok(strError);
|
|
151
|
-
assert.match(strError, /AssertionError/);
|
|
152
|
-
assert.doesNotMatch(strError, /OtherTableError/);
|
|
153
|
-
const skError = extractApplyError(lines, "signalk");
|
|
154
|
-
assert.ok(skError);
|
|
155
|
-
assert.match(skError, /OtherTableError/);
|
|
156
|
-
assert.equal(extractApplyError(lines, "signalk_position"), null);
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
function makeHarness(options = {}) {
|
|
160
|
-
let suspended = [];
|
|
161
|
-
let resumeFailure = null;
|
|
162
|
-
let clock = 1_000_000;
|
|
163
|
-
const harness = {
|
|
164
|
-
resumeCalls: [],
|
|
165
|
-
suspendedCalls: [],
|
|
166
|
-
resolvedCalls: 0,
|
|
167
|
-
errors: [],
|
|
168
|
-
};
|
|
169
|
-
const deps = {
|
|
170
|
-
listSuspended: async () => {
|
|
171
|
-
if (options.failListWith)
|
|
172
|
-
throw options.failListWith;
|
|
173
|
-
return suspended;
|
|
174
|
-
},
|
|
175
|
-
resumeTable: async (name) => {
|
|
176
|
-
harness.resumeCalls.push(name);
|
|
177
|
-
if (resumeFailure)
|
|
178
|
-
throw resumeFailure;
|
|
179
|
-
},
|
|
180
|
-
onSuspended: (tables, anyFailed) => {
|
|
181
|
-
harness.suspendedCalls.push({
|
|
182
|
-
names: tables.map((t) => t.name),
|
|
183
|
-
anyFailed,
|
|
184
|
-
});
|
|
185
|
-
},
|
|
186
|
-
onResolved: () => {
|
|
187
|
-
harness.resolvedCalls++;
|
|
188
|
-
},
|
|
189
|
-
debug: () => { },
|
|
190
|
-
error: (msg) => {
|
|
191
|
-
harness.errors.push(msg);
|
|
192
|
-
},
|
|
193
|
-
};
|
|
194
|
-
harness.monitor = new WalMonitor(deps, {
|
|
195
|
-
retryMinMs: options.retryMinMs ?? 10 * 60_000,
|
|
196
|
-
now: () => clock,
|
|
197
|
-
});
|
|
198
|
-
harness.setSuspended = (tables) => {
|
|
199
|
-
suspended = tables;
|
|
200
|
-
};
|
|
201
|
-
harness.setResumeFailing = (error) => {
|
|
202
|
-
resumeFailure = error;
|
|
203
|
-
};
|
|
204
|
-
harness.advance = (ms) => {
|
|
205
|
-
clock += ms;
|
|
206
|
-
};
|
|
207
|
-
return harness;
|
|
208
|
-
}
|
|
209
|
-
describe("WalMonitor", () => {
|
|
210
|
-
it("attempts one lossless resume on a new suspension and reports pending", async () => {
|
|
211
|
-
const h = makeHarness();
|
|
212
|
-
h.setSuspended([suspendedTable()]);
|
|
213
|
-
await h.monitor.check();
|
|
214
|
-
assert.deepEqual(h.resumeCalls, ["signalk_str"]);
|
|
215
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), "pending");
|
|
216
|
-
assert.deepEqual(h.suspendedCalls, [
|
|
217
|
-
{ names: ["signalk_str"], anyFailed: false },
|
|
218
|
-
]);
|
|
219
|
-
// The snapshot (writerTxn/sequencerTxn/error columns) must be persisted
|
|
220
|
-
// to the log the moment the suspension is seen — the engine-side detail
|
|
221
|
-
// does not survive a container recreate.
|
|
222
|
-
assert.match(h.errors[0], /writerTxn=4672111/);
|
|
223
|
-
});
|
|
224
|
-
it("locks the episode to failed when re-suspended at the same writerTxn", async () => {
|
|
225
|
-
const h = makeHarness();
|
|
226
|
-
h.setSuspended([suspendedTable()]);
|
|
227
|
-
await h.monitor.check();
|
|
228
|
-
await h.monitor.check();
|
|
229
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), "failed");
|
|
230
|
-
assert.deepEqual(h.resumeCalls, ["signalk_str"]);
|
|
231
|
-
assert.equal(h.suspendedCalls[1].anyFailed, true);
|
|
232
|
-
// Still failed on later checks; never resumes again on its own.
|
|
233
|
-
await h.monitor.check();
|
|
234
|
-
assert.deepEqual(h.resumeCalls, ["signalk_str"]);
|
|
235
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), "failed");
|
|
236
|
-
});
|
|
237
|
-
it("starts a fresh episode when the writer advances to a new stall point", async () => {
|
|
238
|
-
const h = makeHarness();
|
|
239
|
-
h.setSuspended([suspendedTable({ writerTxn: 100 })]);
|
|
240
|
-
await h.monitor.check();
|
|
241
|
-
await h.monitor.check();
|
|
242
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), "failed");
|
|
243
|
-
h.setSuspended([suspendedTable({ writerTxn: 200 })]);
|
|
244
|
-
await h.monitor.check();
|
|
245
|
-
assert.deepEqual(h.resumeCalls, ["signalk_str", "signalk_str"]);
|
|
246
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), "pending");
|
|
247
|
-
});
|
|
248
|
-
it("reports resolution exactly once when the suspension clears", async () => {
|
|
249
|
-
const h = makeHarness();
|
|
250
|
-
h.setSuspended([suspendedTable()]);
|
|
251
|
-
await h.monitor.check();
|
|
252
|
-
h.setSuspended([]);
|
|
253
|
-
await h.monitor.check();
|
|
254
|
-
await h.monitor.check();
|
|
255
|
-
assert.equal(h.resolvedCalls, 1);
|
|
256
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), null);
|
|
257
|
-
});
|
|
258
|
-
it("rate-limits resumes across a resume/clear/re-suspend flap at one stall point", async () => {
|
|
259
|
-
const h = makeHarness();
|
|
260
|
-
h.setSuspended([suspendedTable()]);
|
|
261
|
-
await h.monitor.check();
|
|
262
|
-
// Replay makes the table look healthy for one check, then it re-suspends
|
|
263
|
-
// at the same writerTxn (a slow re-failure).
|
|
264
|
-
h.setSuspended([]);
|
|
265
|
-
await h.monitor.check();
|
|
266
|
-
h.setSuspended([suspendedTable()]);
|
|
267
|
-
await h.monitor.check();
|
|
268
|
-
assert.deepEqual(h.resumeCalls, ["signalk_str"]);
|
|
269
|
-
// After the gap passes, one more automatic attempt is allowed.
|
|
270
|
-
h.advance(11 * 60_000);
|
|
271
|
-
h.setSuspended([]);
|
|
272
|
-
await h.monitor.check();
|
|
273
|
-
h.setSuspended([suspendedTable()]);
|
|
274
|
-
await h.monitor.check();
|
|
275
|
-
assert.deepEqual(h.resumeCalls, ["signalk_str", "signalk_str"]);
|
|
276
|
-
});
|
|
277
|
-
it("does not classify a failed resume REQUEST as unreadable data", async () => {
|
|
278
|
-
const h = makeHarness();
|
|
279
|
-
h.setResumeFailing(new Error("table busy"));
|
|
280
|
-
h.setSuspended([suspendedTable()]);
|
|
281
|
-
await h.monitor.check();
|
|
282
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), "pending");
|
|
283
|
-
// The request never executed, so the next check must NOT escalate to
|
|
284
|
-
// "failed" (the panel reads that as corruption) — it stays pending.
|
|
285
|
-
await h.monitor.check();
|
|
286
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), "pending");
|
|
287
|
-
// Once the retry gap passes and a resume actually executes, a
|
|
288
|
-
// re-suspension at the same writerTxn is real evidence — now it fails.
|
|
289
|
-
h.setResumeFailing(null);
|
|
290
|
-
h.advance(11 * 60_000);
|
|
291
|
-
await h.monitor.check();
|
|
292
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), "pending");
|
|
293
|
-
await h.monitor.check();
|
|
294
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), "failed");
|
|
295
|
-
assert.deepEqual(h.resumeCalls, ["signalk_str", "signalk_str"]);
|
|
296
|
-
});
|
|
297
|
-
it("does nothing after stop()", async () => {
|
|
298
|
-
const h = makeHarness();
|
|
299
|
-
h.setSuspended([suspendedTable()]);
|
|
300
|
-
h.monitor.stop();
|
|
301
|
-
await h.monitor.check();
|
|
302
|
-
assert.deepEqual(h.resumeCalls, []);
|
|
303
|
-
assert.deepEqual(h.suspendedCalls, []);
|
|
304
|
-
});
|
|
305
|
-
it("survives a failing wal_tables() probe", async () => {
|
|
306
|
-
const h = makeHarness({ failListWith: new Error("connection refused") });
|
|
307
|
-
await h.monitor.check();
|
|
308
|
-
assert.deepEqual(h.suspendedCalls, []);
|
|
309
|
-
assert.equal(h.resolvedCalls, 0);
|
|
310
|
-
});
|
|
311
|
-
it("handles multiple tables independently", async () => {
|
|
312
|
-
const h = makeHarness();
|
|
313
|
-
h.setSuspended([
|
|
314
|
-
suspendedTable(),
|
|
315
|
-
suspendedTable({ name: "signalk", writerTxn: 900 }),
|
|
316
|
-
]);
|
|
317
|
-
await h.monitor.check();
|
|
318
|
-
assert.deepEqual(h.resumeCalls, ["signalk_str", "signalk"]);
|
|
319
|
-
// signalk recovers, signalk_str stays stuck.
|
|
320
|
-
h.setSuspended([suspendedTable()]);
|
|
321
|
-
await h.monitor.check();
|
|
322
|
-
assert.equal(h.monitor.outcomeFor("signalk_str"), "failed");
|
|
323
|
-
assert.equal(h.monitor.outcomeFor("signalk"), null);
|
|
324
|
-
// Not fully resolved while one table is still suspended.
|
|
325
|
-
assert.equal(h.resolvedCalls, 0);
|
|
326
|
-
});
|
|
327
|
-
});
|
|
328
|
-
describe("isPartitionOpenFailure", () => {
|
|
329
|
-
// Field report (issue #81): power loss left the `_txn` commit record
|
|
330
|
-
// claiming 1,403,951 rows while the column files held 1,402,837. The writer
|
|
331
|
-
// asserts while OPENING the partition, before it reads any transaction, so
|
|
332
|
-
// every RESUME WAL variant re-hits it.
|
|
333
|
-
const partitionOpenStack = [
|
|
334
|
-
"2026-07-21T07:35:50.072000Z C i.q.c.w.ApplyWal2TableJob job failed, table suspended [table=signalk_str~8, seqTxn=57606, error=java.lang.AssertionError",
|
|
335
|
-
"\tat io.questdb.cairo.VarcharTypeDriver.getDataVectorSize(VarcharTypeDriver.java:175)",
|
|
336
|
-
"\tat io.questdb.cairo.TableReader.openPartition(TableReader.java:1234)",
|
|
337
|
-
"]",
|
|
338
|
-
];
|
|
339
|
-
// The class we shipped the guided skip for: the failure is in the pending
|
|
340
|
-
// WAL segment's own files, which a bounded skip really can get past.
|
|
341
|
-
const segmentStack = [
|
|
342
|
-
"2026-07-17T22:22:51.000000Z C i.q.c.w.ApplyWal2TableJob job failed, table suspended [table=signalk_str~8, seqTxn=4672118, error=java.lang.AssertionError",
|
|
343
|
-
"\tat io.questdb.cairo.VarcharTypeDriver.getDataVectorSize(VarcharTypeDriver.java:175)",
|
|
344
|
-
"\tat io.questdb.cairo.wal.TableWriterSegmentFileCache.mmapSegments(TableWriterSegmentFileCache.java:200)",
|
|
345
|
-
"]",
|
|
346
|
-
];
|
|
347
|
-
it("detects a failure while opening the applied partition", () => {
|
|
348
|
-
assert.equal(isPartitionOpenFailure(extractApplyError(partitionOpenStack)), true);
|
|
349
|
-
});
|
|
350
|
-
it("does not flag an unreadable WAL segment, which a skip can repair", () => {
|
|
351
|
-
assert.equal(isPartitionOpenFailure(extractApplyError(segmentStack)), false);
|
|
352
|
-
});
|
|
353
|
-
it("detects every partition-open frame the classifier accepts", () => {
|
|
354
|
-
// Each alternative in the pattern is a distinct way the writer reports
|
|
355
|
-
// dying before it reads a transaction; an untested one can silently stop
|
|
356
|
-
// matching.
|
|
357
|
-
const frames = [
|
|
358
|
-
"io.questdb.cairo.TableReader.openPartition(TableReader.java:1234)",
|
|
359
|
-
"io.questdb.cairo.TableWriter.openLastPartition(TableWriter.java:4242)",
|
|
360
|
-
"io.questdb.cairo.TxReader.unsafeLoadAll(TxReader.java:311)",
|
|
361
|
-
"io.questdb.cairo.ColumnVersionReader.readUnsafe(ColumnVersionReader.java:98)",
|
|
362
|
-
];
|
|
363
|
-
for (const frame of frames) {
|
|
364
|
-
const log = [
|
|
365
|
-
"2026-07-21T07:35:50.072000Z C i.q.c.w.ApplyWal2TableJob job failed, table suspended [table=signalk_str~8, error=java.lang.AssertionError",
|
|
366
|
-
`\tat ${frame}`,
|
|
367
|
-
"]",
|
|
368
|
-
];
|
|
369
|
-
assert.equal(isPartitionOpenFailure(extractApplyError(log)), true, `expected ${frame} to classify as a partition-open failure`);
|
|
370
|
-
}
|
|
371
|
-
});
|
|
372
|
-
it("does not classify on the table name or error prose", () => {
|
|
373
|
-
// The captured entry includes QuestDB's `[table=..., error=...]` header.
|
|
374
|
-
// Matching a bare word anywhere in it would misfire on a user's table
|
|
375
|
-
// name or on wording inside an unrelated error — and a false positive
|
|
376
|
-
// withholds a skip that would actually have repaired the table.
|
|
377
|
-
const tableNamed = [
|
|
378
|
-
"2026-07-21T07:35:50.072000Z C i.q.c.w.ApplyWal2TableJob job failed, table suspended [table=openPartition~3, error=io.questdb.cairo.CairoException: could not open, out of disk space",
|
|
379
|
-
"]",
|
|
380
|
-
];
|
|
381
|
-
const prose = [
|
|
382
|
-
"2026-07-21T07:35:50.072000Z C i.q.c.w.ApplyWal2TableJob job failed, table suspended [table=signalk~3, error=io.questdb.cairo.CairoException: openPartition budget exceeded",
|
|
383
|
-
"]",
|
|
384
|
-
];
|
|
385
|
-
assert.equal(isPartitionOpenFailure(extractApplyError(tableNamed)), false);
|
|
386
|
-
assert.equal(isPartitionOpenFailure(extractApplyError(prose)), false);
|
|
387
|
-
});
|
|
388
|
-
it("does not classify a same-named frame from another library", () => {
|
|
389
|
-
// The method names are not unique to QuestDB; without the namespace
|
|
390
|
-
// anchor an unrelated dependency's frame would suppress a valid skip.
|
|
391
|
-
const foreign = [
|
|
392
|
-
"2026-07-21T07:35:50.072000Z C i.q.c.w.ApplyWal2TableJob job failed, table suspended [table=signalk~3, error=java.lang.AssertionError",
|
|
393
|
-
"\tat com.example.storage.Writer.openPartition(Writer.java:88)",
|
|
394
|
-
"]",
|
|
395
|
-
];
|
|
396
|
-
assert.equal(isPartitionOpenFailure(extractApplyError(foreign)), false);
|
|
397
|
-
});
|
|
398
|
-
it("treats a missing diagnosis as not-this-class", () => {
|
|
399
|
-
// No engine log (container recreated, log API unavailable): must not
|
|
400
|
-
// withhold the skip on speculation.
|
|
401
|
-
assert.equal(isPartitionOpenFailure(null), false);
|
|
402
|
-
assert.equal(isPartitionOpenFailure(""), false);
|
|
403
|
-
});
|
|
404
|
-
});
|
|
405
|
-
//# sourceMappingURL=wal-monitor.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"wal-monitor.test.js","sourceRoot":"","sources":["../../src/test/wal-monitor.test.ts"],"names":[],"mappings":"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"}
|