querysub 0.611.0 → 0.612.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 +2 -2
- package/src/4-deploy/edgeNodes.ts +16 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "querysub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.612.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"node-forge": "https://github.com/sliftist/forge#e618181b469b07bdc70b968b0391beb8ef5fecd6",
|
|
76
76
|
"pako": "^2.1.0",
|
|
77
77
|
"peggy": "^5.0.6",
|
|
78
|
-
"sliftutils": "^1.7.
|
|
78
|
+
"sliftutils": "^1.7.85",
|
|
79
79
|
"socket-function": "^1.2.30",
|
|
80
80
|
"terser": "^5.31.0",
|
|
81
81
|
"typenode": "^6.6.1",
|
|
@@ -26,6 +26,8 @@ import { getGitRefLive, getGitURLLive } from "./git";
|
|
|
26
26
|
import { DeployProgress } from "./deployFunctions";
|
|
27
27
|
import { PromiseObj } from "../promise";
|
|
28
28
|
import type { FunctionRunnerIndex } from "../4-querysub/FunctionRunnerTracking";
|
|
29
|
+
import { isDefined } from "sliftutils/misc/types";
|
|
30
|
+
|
|
29
31
|
const UPDATE_POLL_INTERVAL = timeInMinute * 15;
|
|
30
32
|
const HEARTBEAT_INTERVAL = timeInMinute;
|
|
31
33
|
const EDGE_NODE_DELETE_THRESHOLD = timeInMinute * 15;
|
|
@@ -34,11 +36,8 @@ const EDGE_NODE_READ_PARALLEL = 64;
|
|
|
34
36
|
export const edgeNodeStorage = isNodeTrue() && getArchives2BufferedPublic("edgenodes2/");
|
|
35
37
|
export const edgeNodeIndexFile = "edge-nodes-index.json";
|
|
36
38
|
|
|
37
|
-
let registeredNodePaths = new Set<string>();
|
|
38
39
|
function getNextNodePath() {
|
|
39
|
-
|
|
40
|
-
registeredNodePaths.add(path);
|
|
41
|
-
return path;
|
|
40
|
+
return "node0_" + getOwnNodeId();
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
let edgeShutdown = false;
|
|
@@ -94,6 +93,7 @@ declare global {
|
|
|
94
93
|
var EDGE_NODE_STATS: EdgeNodeStats | undefined;
|
|
95
94
|
}
|
|
96
95
|
let registeredEdgeNode: { host: string; entryPaths: string[] } | boolean | undefined;
|
|
96
|
+
let lastEdgeNodeConfig: EdgeNodeConfig | undefined;
|
|
97
97
|
export async function registerEdgeNode(config: {
|
|
98
98
|
host: string;
|
|
99
99
|
entryPaths: string[];
|
|
@@ -114,9 +114,7 @@ export async function registerEdgeNode(config: {
|
|
|
114
114
|
registerShutdownHandler(async () => {
|
|
115
115
|
edgeShutdown = true;
|
|
116
116
|
console.log(magenta(`Removing node from edge node list due to shutdown`));
|
|
117
|
-
await
|
|
118
|
-
await edgeNodeStorage.del(nodePath);
|
|
119
|
-
}));
|
|
117
|
+
await edgeNodeStorage.del(getNextNodePath());
|
|
120
118
|
await updateEdgeNodesFile();
|
|
121
119
|
});
|
|
122
120
|
const { watchScheduledShutdown } = await import("../-g-core-values/scheduledShutdown");
|
|
@@ -128,9 +126,7 @@ export async function registerEdgeNode(config: {
|
|
|
128
126
|
// Wait a bit to fully remove ourself from the edge node list
|
|
129
127
|
await delay(Math.max(0, duration * 0.2));
|
|
130
128
|
console.log(magenta(`Removing node from edge node list due to scheduled shutdown at ${new Date(time).toLocaleString()}`));
|
|
131
|
-
await
|
|
132
|
-
await edgeNodeStorage.del(nodePath);
|
|
133
|
-
}));
|
|
129
|
+
await edgeNodeStorage.del(getNextNodePath());
|
|
134
130
|
await updateEdgeNodesFile();
|
|
135
131
|
})();
|
|
136
132
|
});
|
|
@@ -177,7 +173,7 @@ export async function registerEdgeNode(config: {
|
|
|
177
173
|
public: isPublic(),
|
|
178
174
|
functionRunnerIndex: await getInitialFunctionRunnerIndex(),
|
|
179
175
|
};
|
|
180
|
-
|
|
176
|
+
lastEdgeNodeConfig = edgeNodeConfig;
|
|
181
177
|
await edgeNodeStorage.set(getNextNodePath(), Buffer.from(JSON.stringify(edgeNodeConfig)));
|
|
182
178
|
}
|
|
183
179
|
registeredEdgeNode = {
|
|
@@ -229,6 +225,7 @@ const loadEntryPointsByHash = runInSerial(async function loadEntryPointsByHash(c
|
|
|
229
225
|
public: isPublic(),
|
|
230
226
|
functionRunnerIndex: await getInitialFunctionRunnerIndex(),
|
|
231
227
|
};
|
|
228
|
+
lastEdgeNodeConfig = edgeNodeConfig;
|
|
232
229
|
|
|
233
230
|
await edgeNodeStorage.set(getNextNodePath(), Buffer.from(JSON.stringify(edgeNodeConfig)));
|
|
234
231
|
console.log(magenta(`Registered edge node`), edgeNodeConfig);
|
|
@@ -245,14 +242,9 @@ async function getInitialFunctionRunnerIndex(): Promise<FunctionRunnerIndex | un
|
|
|
245
242
|
}
|
|
246
243
|
|
|
247
244
|
async function publishOwnScheduledShutdown(time: number) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
let config: EdgeNodeConfig = JSON.parse(buffer.toString());
|
|
252
|
-
if (config.scheduledShutdownTime === time) continue;
|
|
253
|
-
config.scheduledShutdownTime = time;
|
|
254
|
-
await edgeNodeStorage.set(nodePath, Buffer.from(JSON.stringify(config)));
|
|
255
|
-
}
|
|
245
|
+
if (!lastEdgeNodeConfig) return;
|
|
246
|
+
lastEdgeNodeConfig.scheduledShutdownTime = time;
|
|
247
|
+
await edgeNodeStorage.set(getNextNodePath(), Buffer.from(JSON.stringify(lastEdgeNodeConfig)));
|
|
256
248
|
await updateEdgeNodesFile();
|
|
257
249
|
}
|
|
258
250
|
|
|
@@ -271,12 +263,10 @@ const startUpdateLoop = lazy(async () => {
|
|
|
271
263
|
|
|
272
264
|
async function heartbeatLoop() {
|
|
273
265
|
if (edgeShutdown) return;
|
|
266
|
+
if (!lastEdgeNodeConfig) return;
|
|
274
267
|
let nodePath = getNextNodePath();
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
let config: EdgeNodeConfig = JSON.parse(buffer.toString());
|
|
278
|
-
config.heartbeatTime = Date.now();
|
|
279
|
-
await edgeNodeStorage.set(nodePath, Buffer.from(JSON.stringify(config)));
|
|
268
|
+
lastEdgeNodeConfig.heartbeatTime = Date.now();
|
|
269
|
+
await edgeNodeStorage.set(nodePath, Buffer.from(JSON.stringify(lastEdgeNodeConfig)));
|
|
280
270
|
// Push the fresh heartbeat into the index so clients see it (they read only the index, not the per-node files).
|
|
281
271
|
await updateEdgeNodesFile();
|
|
282
272
|
}
|
|
@@ -287,7 +277,6 @@ async function updateLoop() {
|
|
|
287
277
|
}
|
|
288
278
|
|
|
289
279
|
async function updateEdgeNodesFile() {
|
|
290
|
-
// Snapshot the time BEFORE reading anything below. Staleness is judged against when we STARTED, so if the reads block we can never mass-evict live nodes just because wall-clock advanced while we were stuck.
|
|
291
280
|
let now = Date.now();
|
|
292
281
|
|
|
293
282
|
let prevEdgeNodeFile = await edgeNodeStorage.get(edgeNodeIndexFile);
|
|
@@ -318,7 +307,6 @@ async function updateEdgeNodesFile() {
|
|
|
318
307
|
let edgeNodeFiles = await edgeNodeStorage.find("node", { type: "files" });
|
|
319
308
|
// Reads are independent, so run them in parallel (bounded): with many files a serial pass would take files × read-latency, which could be minutes.
|
|
320
309
|
let readEdgeNodeFile = runInParallel({ parallelCount: EDGE_NODE_READ_PARALLEL }, async (nodeFile: string) => {
|
|
321
|
-
// Read directly, not through a cache: heartbeatTime mutates every minute, so a cached config would report a stale heartbeat and wrongly evict a live peer.
|
|
322
310
|
let buffer = await edgeNodeStorage.get(nodeFile);
|
|
323
311
|
if (!buffer) return undefined;
|
|
324
312
|
let config: EdgeNodeConfig = JSON.parse(buffer.toString());
|
|
@@ -330,19 +318,9 @@ async function updateEdgeNodesFile() {
|
|
|
330
318
|
}
|
|
331
319
|
return config;
|
|
332
320
|
});
|
|
333
|
-
let configs = await Promise.all(edgeNodeFiles.map(readEdgeNodeFile));
|
|
334
|
-
|
|
335
|
-
let bestByNodeId = new Map<string, EdgeNodeConfig>();
|
|
336
|
-
for (let config of configs) {
|
|
337
|
-
if (!config) continue;
|
|
338
|
-
// One entry per nodeId (re-registrations can leave more than one), keeping the freshest heartbeat.
|
|
339
|
-
let existing = bestByNodeId.get(config.nodeId);
|
|
340
|
-
if (!existing || (config.heartbeatTime || config.bootTime) > (existing.heartbeatTime || existing.bootTime)) {
|
|
341
|
-
bestByNodeId.set(config.nodeId, config);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
321
|
+
let configs = (await Promise.all(edgeNodeFiles.map(readEdgeNodeFile))).filter(isDefined);
|
|
344
322
|
|
|
345
|
-
let newEdgeNodes = sort(
|
|
323
|
+
let newEdgeNodes = sort(configs, x => -(x.heartbeatTime || x.bootTime));
|
|
346
324
|
let newEdgeNodeIndex: EdgeNodesIndex = {
|
|
347
325
|
edgeNodes: newEdgeNodes,
|
|
348
326
|
liveHash,
|