querysub 0.20.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/-f-node-discovery/NodeDiscovery.ts +2 -0
- package/src/0-path-value-core/NodePathAuthorities.ts +3 -1
- package/src/2-proxy/PathValueProxyWatcher.ts +3 -3
- package/src/3-path-functions/pathFunctionLoader.ts +5 -1
- package/src/5-diagnostics/nodeMetadata.ts +15 -5
- package/src/diagnostics/NodeViewer.tsx +13 -6
- package/src/diagnostics/logs/DiskLoggerPage.tsx +3 -3
- package/src/diagnostics/logs/diskLogger.ts +3 -1
- package/src/diagnostics/trackResources.ts +1 -1
package/package.json
CHANGED
|
@@ -351,6 +351,8 @@ async function runMainSyncLoops(discoveryReady: PromiseObj<void>) {
|
|
|
351
351
|
await timeoutToUndefinedSilent(timeInSecond * 5, errorToUndefinedSilent(NodeDiscoveryController.nodes[nodeId].addNode(getOwnNodeId())));
|
|
352
352
|
}));
|
|
353
353
|
|
|
354
|
+
console.log(magenta(`Node discovery is ready and first heartbeat + sync is done`));
|
|
355
|
+
|
|
354
356
|
await runInfinitePoll(HEARTBEAT_INTERVAL, async function nodeDiscoverHeartbeat() {
|
|
355
357
|
// If we waited too long, other nodes might think we are dead. In which case, we SHOULD terminate.
|
|
356
358
|
if (!isNoNetwork()) {
|
|
@@ -230,6 +230,7 @@ class NodePathAuthorities {
|
|
|
230
230
|
return;
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
let time = Date.now();
|
|
233
234
|
let createTime = await errorToUndefinedSilent(PathController.nodes[nodeId].getCreateTime());
|
|
234
235
|
if (createTime === undefined) {
|
|
235
236
|
// Don't log for 127-0-0-1, as it usually fails, and is mostly a development optimization
|
|
@@ -238,7 +239,8 @@ class NodePathAuthorities {
|
|
|
238
239
|
}
|
|
239
240
|
return;
|
|
240
241
|
}
|
|
241
|
-
|
|
242
|
+
time = Date.now() - time;
|
|
243
|
+
console.log(blue(`Identifying ${nodeId} as a path authority. ping latency = ${formatTime(time)}`));
|
|
242
244
|
this.authorities.set(nodeId, {
|
|
243
245
|
nodeId,
|
|
244
246
|
self: nodeId.startsWith("127-0-0-1."),
|
|
@@ -23,7 +23,7 @@ import { LOCAL_DOMAIN_PATH } from "../0-path-value-core/NodePathAuthorities";
|
|
|
23
23
|
import { registerPeriodic } from "../diagnostics/periodic";
|
|
24
24
|
import { remoteWatcher } from "../1-path-client/RemoteWatcher";
|
|
25
25
|
import { Schema2, Schema2Fncs } from "./schema2";
|
|
26
|
-
import { devDebugbreak, getDomain } from "../config";
|
|
26
|
+
import { devDebugbreak, getDomain, isPublic } from "../config";
|
|
27
27
|
|
|
28
28
|
import type { CallSpec } from "../3-path-functions/PathFunctionRunner";
|
|
29
29
|
import type { FunctionMetadata } from "../3-path-functions/syncSchema";
|
|
@@ -1813,9 +1813,9 @@ export function registerSchemaPrefix(config: {
|
|
|
1813
1813
|
if (!list) {
|
|
1814
1814
|
schemaPrefixes.push(list = { len, prefixes: new Map() });
|
|
1815
1815
|
}
|
|
1816
|
-
if (isNode()) {
|
|
1816
|
+
if (isNode() && !globalThis.isHotReloading?.()) {
|
|
1817
1817
|
if (list.prefixes.has(config.prefixPathStr)) {
|
|
1818
|
-
throw new Error(`Prefix matches only work due to only having one version of the code ever load (except for during hot reloading development clientside). If we try to render multiple versions of the same code serverside (ex, because we pre-loaded new code during a deploy), it will break, as we can't distinguish them. ADD GIT HASH TO PREFIX SCHEMAS TO FIX THIS
|
|
1818
|
+
throw new Error(`Prefix matches only work due to only having one version of the code ever load (except for during hot reloading development clientside). If we try to render multiple versions of the same code serverside (ex, because we pre-loaded new code during a deploy), it will break, as we can't distinguish them. ADD GIT HASH TO PREFIX SCHEMAS TO FIX THIS! Tried to double load ${config.prefixPathStr}`);
|
|
1819
1819
|
}
|
|
1820
1820
|
}
|
|
1821
1821
|
list.prefixes.set(config.prefixPathStr, config.schema);
|
|
@@ -16,7 +16,7 @@ import { isNode, isNodeTrue, nextId, timeInSecond } from "socket-function/src/mi
|
|
|
16
16
|
import { getPathStr2, getPathStr3 } from "../path";
|
|
17
17
|
import { consistentHash } from "../misc/hash";
|
|
18
18
|
import { setExternalHotReloading } from "socket-function/hot/HotReloadController";
|
|
19
|
-
import { isPublic } from "../config";
|
|
19
|
+
import { devDebugbreak, isPublic } from "../config";
|
|
20
20
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
21
21
|
import { requiresNetworkTrustHook } from "../-d-trust/NetworkTrust2";
|
|
22
22
|
import { getControllerNodeId, getControllerNodeIdList } from "../-g-core-values/NodeCapabilities";
|
|
@@ -281,6 +281,10 @@ async function getModuleFromSpecBase(
|
|
|
281
281
|
deployPath = packagePath + "deploy.ts";
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
+
if (path.startsWith("/root")) {
|
|
285
|
+
devDebugbreak();
|
|
286
|
+
}
|
|
287
|
+
|
|
284
288
|
console.log(blue(`require(${JSON.stringify(path)})`));
|
|
285
289
|
|
|
286
290
|
// Set functionSpec for the next synchronous evaluation
|
|
@@ -6,10 +6,11 @@ import { requiresNetworkTrustHook } from "../-d-trust/NetworkTrust2";
|
|
|
6
6
|
import { cache } from "socket-function/src/caching";
|
|
7
7
|
import { TimeGrouper } from "./TimeGrouper";
|
|
8
8
|
import { runInfinitePollCallAtStart } from "socket-function/src/batching";
|
|
9
|
-
import { timeInMinute } from "socket-function/src/misc";
|
|
9
|
+
import { throttleFunction, timeInMinute } from "socket-function/src/misc";
|
|
10
10
|
import { formatNumber, formatPercent, formatTime } from "socket-function/src/formatting/format";
|
|
11
11
|
import os from "os";
|
|
12
12
|
import { isNode } from "typesafecss";
|
|
13
|
+
import { diskLog } from "../diagnostics/logs/diskLogger";
|
|
13
14
|
|
|
14
15
|
// Undefined means we infer the column
|
|
15
16
|
// Null means the column is removed
|
|
@@ -40,8 +41,12 @@ export function registerNodeMetadata(getter: ExtraMetadata) {
|
|
|
40
41
|
|
|
41
42
|
let stateValues = cache((title: string, format: (value: number) => string): { (value: number): void } => {
|
|
42
43
|
let timeGrouper = new TimeGrouper();
|
|
44
|
+
let logToDisk = throttleFunction(timeInMinute, (value: number) => {
|
|
45
|
+
diskLog(title, { value, formatted: format(value) });
|
|
46
|
+
});
|
|
43
47
|
function onValue(value: number) {
|
|
44
48
|
timeGrouper.onValueChanged(value);
|
|
49
|
+
void logToDisk(value);
|
|
45
50
|
}
|
|
46
51
|
registerNodeMetadata({
|
|
47
52
|
columnName: title,
|
|
@@ -54,8 +59,12 @@ let stateValues = cache((title: string, format: (value: number) => string): { (v
|
|
|
54
59
|
});
|
|
55
60
|
let eventValues = cache((title: string, format: (value: number) => string): { (value: number): void } => {
|
|
56
61
|
let timeGrouper = new TimeGrouper();
|
|
62
|
+
let logToDisk = throttleFunction(timeInMinute, (value: number) => {
|
|
63
|
+
diskLog(title, { value, formatted: format(value) });
|
|
64
|
+
});
|
|
57
65
|
function onValue(value: number) {
|
|
58
66
|
timeGrouper.onValueChanged(value);
|
|
67
|
+
void logToDisk(value);
|
|
59
68
|
}
|
|
60
69
|
registerNodeMetadata({
|
|
61
70
|
columnName: title,
|
|
@@ -81,11 +90,11 @@ if (isNode()) {
|
|
|
81
90
|
const free = os.freemem();
|
|
82
91
|
const total = os.totalmem();
|
|
83
92
|
|
|
84
|
-
let constrainedMemory = process.constrainedMemory();
|
|
85
|
-
|
|
86
93
|
logNodeStateStats("System|Memory Free", x => formatNumber(x) + "B")(free);
|
|
87
94
|
logNodeStateStats("System|Memory Free %", formatPercent)(free / total);
|
|
88
|
-
|
|
95
|
+
|
|
96
|
+
let constrainedMemory = process.constrainedMemory();
|
|
97
|
+
if (constrainedMemory !== undefined && constrainedMemory < 2 ** 48) {
|
|
89
98
|
logNodeStateStats("System|Constrained Memory", x => formatNumber(x) + "B")(constrainedMemory);
|
|
90
99
|
}
|
|
91
100
|
|
|
@@ -97,7 +106,8 @@ if (isNode()) {
|
|
|
97
106
|
logNodeStateStats("System|CPU Count", formatNumber)(cpuCount);
|
|
98
107
|
|
|
99
108
|
let load = os.loadavg();
|
|
100
|
-
logNodeStateStats("System|Average
|
|
109
|
+
logNodeStateStats("System|Average Load", formatPercent)(load[0]);
|
|
110
|
+
logNodeStateStats("System|Average Free Cores", formatPercent)((os.cpus().length - load[0]));
|
|
101
111
|
|
|
102
112
|
});
|
|
103
113
|
}
|
|
@@ -54,7 +54,7 @@ type NodeData = {
|
|
|
54
54
|
columns: ColumnsType;
|
|
55
55
|
row: RowType;
|
|
56
56
|
};
|
|
57
|
-
|
|
57
|
+
loadTime?: number;
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
module.hotreload = true;
|
|
@@ -81,6 +81,7 @@ export class NodeViewer extends qreact.Component {
|
|
|
81
81
|
let ourIP = await controller.getCallerIP();
|
|
82
82
|
|
|
83
83
|
await Promise.allSettled(nodeIds.map(async nodeId => {
|
|
84
|
+
let time = Date.now();
|
|
84
85
|
let data: NodeData = { nodeId };
|
|
85
86
|
try {
|
|
86
87
|
data.table = await controller.getMiscInfo(nodeId);
|
|
@@ -100,6 +101,8 @@ export class NodeViewer extends qreact.Component {
|
|
|
100
101
|
} catch (e: any) {
|
|
101
102
|
data.apiError = "Error: " + e.stack;
|
|
102
103
|
}
|
|
104
|
+
time = Date.now() - time;
|
|
105
|
+
data.loadTime = time;
|
|
103
106
|
Querysub.commit(() => {
|
|
104
107
|
this.state.nodes[nodeId] = atomicObjectWrite(data);
|
|
105
108
|
});
|
|
@@ -182,7 +185,7 @@ export class NodeViewer extends qreact.Component {
|
|
|
182
185
|
}
|
|
183
186
|
|
|
184
187
|
let builtinGroups = {
|
|
185
|
-
"Default": ["buttons", "devToolsURL", "nodeId", "ip", "uptime", "Heap", "All Memory", "Blocking Lag", "port", "threadId", "machineId", "apiError", "live_entryPoint"],
|
|
188
|
+
"Default": ["buttons", "devToolsURL", "nodeId", "ip", "uptime", "loadTime", "Heap", "All Memory", "Blocking Lag", "port", "threadId", "machineId", "apiError", "live_entryPoint"],
|
|
186
189
|
};
|
|
187
190
|
// Column => group
|
|
188
191
|
let builtInGroupsLookup = new Map<string, string>();
|
|
@@ -263,7 +266,6 @@ export class NodeViewer extends qreact.Component {
|
|
|
263
266
|
formatter: (obj) => {
|
|
264
267
|
let str = String(obj);
|
|
265
268
|
if (str.startsWith("http")) return formatValue(obj);
|
|
266
|
-
https://noproxy.querysub.com:1111/?page=test&showingmanagement&managementpage=DiskLoggerPage&nodeId=b4d19fba5f79d48c3.b68f46ffaffad0636.querysub.com%3A41863&filter=%22%5C%22__nodeId%5C%22%3A%5C%22b654f522bf3a67c49.b68f46ffaffad0636.querysub.com%3A33473%5C%22%22
|
|
267
269
|
|
|
268
270
|
return (
|
|
269
271
|
<ATag values={[
|
|
@@ -277,6 +279,7 @@ export class NodeViewer extends qreact.Component {
|
|
|
277
279
|
},
|
|
278
280
|
},
|
|
279
281
|
ip: {},
|
|
282
|
+
loadTime: { formatter: "timeSpan" },
|
|
280
283
|
...x.table?.columns,
|
|
281
284
|
//capabilities: null,
|
|
282
285
|
apiError: { formatter: "error" },
|
|
@@ -353,8 +356,12 @@ class NodeViewerControllerBase {
|
|
|
353
356
|
await forwardPort({ internalPort: externalPort, externalPort: externalPort, });
|
|
354
357
|
|
|
355
358
|
tlsServer.on("secureConnection", (socket) => {
|
|
356
|
-
|
|
357
|
-
|
|
359
|
+
let matchedIP = (
|
|
360
|
+
socket.remoteAddress === callerIP ||
|
|
361
|
+
callerIP === "127.0.0.1" && socket.remoteAddress === ourIP
|
|
362
|
+
);
|
|
363
|
+
if (!matchedIP) {
|
|
364
|
+
console.error(`Rejecting connection from ${socket.remoteAddress}, expected ${callerIP} ${callerIP === "127.0.0.1" && `or ${ourIP}` || ""}`);
|
|
358
365
|
socket.end();
|
|
359
366
|
return;
|
|
360
367
|
}
|
|
@@ -375,7 +382,7 @@ class NodeViewerControllerBase {
|
|
|
375
382
|
let ourDomain = ourIP.replaceAll(".", "-") + "." + getDomain();
|
|
376
383
|
await setRecord("A", ourDomain, ourIP);
|
|
377
384
|
|
|
378
|
-
console.log(
|
|
385
|
+
console.log(`Inspect forward ${ourDomain}:${finalPort} => ${baseNodeIPResolved}:${externalPort} => 127.0.0.1:${internalPort}, for ${callerIP}`);
|
|
379
386
|
|
|
380
387
|
return internalInspectURL.replace(`ws=127.0.0.1:${internalPort}`, `wss=${ourDomain}:${finalPort}`);
|
|
381
388
|
}
|
|
@@ -182,7 +182,7 @@ export class DiskLoggerPage extends qreact.Component {
|
|
|
182
182
|
if (!canHaveChildren(value)) {
|
|
183
183
|
// Add to search as well
|
|
184
184
|
if (filterURL.value.trim()) {
|
|
185
|
-
filterURL.value += "
|
|
185
|
+
filterURL.value += " & ";
|
|
186
186
|
}
|
|
187
187
|
filterURL.value += String(value);
|
|
188
188
|
}
|
|
@@ -244,17 +244,17 @@ export class DiskLoggerPage extends qreact.Component {
|
|
|
244
244
|
};
|
|
245
245
|
|
|
246
246
|
table.columns["remaining"] = {
|
|
247
|
+
title: "Object",
|
|
247
248
|
formatter(value, context) {
|
|
248
249
|
return <ObjectDisplay
|
|
249
250
|
value={context?.row}
|
|
250
|
-
excludedFields={fullSelectedFields}
|
|
251
251
|
onClickKey={path => addPath(path)}
|
|
252
252
|
onClickValue={(path, value) => {
|
|
253
253
|
addPath(path);
|
|
254
254
|
if (!canHaveChildren(value)) {
|
|
255
255
|
// Add to search as well
|
|
256
256
|
if (filterURL.value.trim()) {
|
|
257
|
-
filterURL.value += "
|
|
257
|
+
filterURL.value += " & ";
|
|
258
258
|
}
|
|
259
259
|
filterURL.value += String(value);
|
|
260
260
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import { batchFunction, runInfinitePoll } from "socket-function/src/batching";
|
|
3
|
-
import { timeInDay, timeInHour } from "socket-function/src/misc";
|
|
3
|
+
import { nextId, timeInDay, timeInHour } from "socket-function/src/misc";
|
|
4
4
|
import { getStorageDir, getStorageFolder } from "../../fs";
|
|
5
5
|
import fs from "fs";
|
|
6
6
|
import { canHaveChildren } from "socket-function/src/types";
|
|
@@ -188,9 +188,11 @@ function safeCopyObject<T>(obj: T): T {
|
|
|
188
188
|
return { errorCopying: e.messsage } as any;
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
|
+
let __baseThreadId = nextId();
|
|
191
192
|
function packageLogObj(args: unknown[]): LogObj {
|
|
192
193
|
let logObj: LogObj = {
|
|
193
194
|
time: Date.now(),
|
|
195
|
+
__baseThreadId,
|
|
194
196
|
};
|
|
195
197
|
for (let part of globalContextParts) {
|
|
196
198
|
Object.assign(logObj, safeCopyObject(part()));
|