envio 3.12.1 → 3.13.0-rc.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 +6 -8
- package/src/BatchProcessing.res +15 -14
- package/src/BatchProcessing.res.mjs +8 -15
- package/src/Bin.res +24 -17
- package/src/Bin.res.mjs +5 -0
- package/src/ChainFetching.res +18 -24
- package/src/ChainFetching.res.mjs +14 -15
- package/src/ChainState.res +103 -38
- package/src/ChainState.res.mjs +79 -22
- package/src/ChainState.resi +14 -2
- package/src/Config.res +32 -0
- package/src/Config.res.mjs +24 -0
- package/src/Core.res +4 -0
- package/src/Core.res.mjs +4 -0
- package/src/CrossChainState.res +109 -11
- package/src/CrossChainState.res.mjs +71 -7
- package/src/CrossChainState.resi +11 -1
- package/src/Env.res +4 -0
- package/src/ErrorHandling.res +15 -4
- package/src/ErrorHandling.res.mjs +16 -5
- package/src/FinalizeBackfill.res +10 -4
- package/src/FinalizeBackfill.res.mjs +5 -3
- package/src/HandlerRegister.res +0 -37
- package/src/HandlerRegister.res.mjs +0 -18
- package/src/IndexerLoop.res +2 -0
- package/src/IndexerLoop.res.mjs +1 -0
- package/src/IndexerState.res +43 -1
- package/src/IndexerState.res.mjs +48 -4
- package/src/IndexerState.resi +11 -0
- package/src/Main.res +128 -268
- package/src/Main.res.mjs +27 -153
- package/src/Metrics.res +268 -102
- package/src/Metrics.res.mjs +227 -48
- package/src/Persistence.res +30 -2
- package/src/Persistence.res.mjs +12 -3
- package/src/PgStorage.res +19 -11
- package/src/PgStorage.res.mjs +13 -10
- package/src/Rollback.res +3 -3
- package/src/Server.res +178 -0
- package/src/Server.res.mjs +143 -0
- package/src/SimulateItems.res +1 -1
- package/src/SimulateItems.res.mjs +1 -1
- package/src/Supervisor.res +542 -0
- package/src/Supervisor.res.mjs +455 -0
- package/src/TestIndexer.res +1 -1
- package/src/TestIndexer.res.mjs +2 -2
- package/src/Worker.res +101 -0
- package/src/Worker.res.mjs +81 -0
- package/src/bindings/NodeJs.res +50 -0
- package/src/bindings/NodeJs.res.mjs +8 -1
- package/src/db/InternalTable.res +8 -1
- package/src/db/InternalTable.res.mjs +5 -1
- package/src/sources/AddressSet.res +5 -3
- package/src/sources/AddressStore.res +19 -11
- package/src/sources/AddressStore.res.mjs +2 -7
- package/src/sources/BlockStore.res +10 -9
- package/src/sources/BlockStore.res.mjs +4 -4
- package/src/sources/ChainSources.res +4 -0
- package/src/sources/ChainSources.res.mjs +2 -2
- package/src/sources/EvmChain.res +4 -0
- package/src/sources/EvmChain.res.mjs +3 -1
- package/src/sources/EvmEventItem.res +56 -0
- package/src/sources/EvmEventItem.res.mjs +32 -0
- package/src/sources/EvmHyperSyncSource.res +7 -37
- package/src/sources/EvmHyperSyncSource.res.mjs +8 -29
- package/src/sources/EvmRpcClient.res +41 -59
- package/src/sources/EvmRpcClient.res.mjs +4 -54
- package/src/sources/EvmRpcWs.res +4 -1
- package/src/sources/EvmRpcWs.res.mjs +6 -2
- package/src/sources/FuelHyperSyncSource.res +6 -4
- package/src/sources/FuelHyperSyncSource.res.mjs +7 -9
- package/src/sources/HeightFeed.res +7 -1
- package/src/sources/HeightFeed.res.mjs +9 -7
- package/src/sources/HyperSyncClient.res +1 -14
- package/src/sources/RequestStat.res +7 -0
- package/src/sources/RequestStat.res.mjs +14 -1
- package/src/sources/RpcSource.res +100 -1043
- package/src/sources/RpcSource.res.mjs +81 -1056
- package/src/sources/SimulateSource.res +2 -5
- package/src/sources/SimulateSource.res.mjs +2 -3
- package/src/sources/Source.res +34 -12
- package/src/sources/Source.res.mjs +11 -0
- package/src/sources/SourceManager.res +111 -31
- package/src/sources/SourceManager.res.mjs +65 -31
- package/src/sources/SourceManager.resi +4 -0
- package/src/sources/StartBlockResolver.res +8 -5
- package/src/sources/StartBlockResolver.res.mjs +4 -2
- package/src/sources/SvmHyperSyncSource.res +4 -2
- package/src/sources/SvmHyperSyncSource.res.mjs +4 -6
- package/src/sources/TransactionStore.res +9 -6
- package/src/sources/TransactionStore.res.mjs +2 -2
- package/src/tui/Tui.res +10 -0
- package/src/tui/Tui.res.mjs +15 -0
- package/src/tui/components/SyncETA.res +12 -6
- package/src/tui/components/SyncETA.res.mjs +12 -8
- package/src/LazyLoader.res +0 -135
- package/src/LazyLoader.res.mjs +0 -118
- package/src/bindings/SDSL.res +0 -12
- package/src/bindings/SDSL.res.mjs +0 -9
- package/src/bindings/Yargs.res +0 -8
- package/src/bindings/Yargs.res.mjs +0 -2
- package/src/sources/Rpc.res +0 -185
- package/src/sources/Rpc.res.mjs +0 -183
package/src/Metrics.res.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import * as ChainId from "./ChainId.res.mjs";
|
|
|
6
6
|
import * as Process from "process";
|
|
7
7
|
import * as Perf_hooks from "perf_hooks";
|
|
8
8
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
9
|
+
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
9
10
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
10
11
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
11
12
|
|
|
@@ -18,6 +19,94 @@ function hasProcessedToEndblock(m) {
|
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
function sumByKey(items, key, add) {
|
|
23
|
+
let byKey = {};
|
|
24
|
+
let order = [];
|
|
25
|
+
items.forEach(item => {
|
|
26
|
+
let k = key(item);
|
|
27
|
+
let existing = byKey[k];
|
|
28
|
+
if (existing !== undefined) {
|
|
29
|
+
byKey[k] = add(Primitive_option.valFromOption(existing), item);
|
|
30
|
+
} else {
|
|
31
|
+
byKey[k] = item;
|
|
32
|
+
order.push(k);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return order.map(k => byKey[k]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function merge(snapshots, startTime, metricTime, elapsedSeconds, targetBufferSize) {
|
|
39
|
+
let sumInt = select => Stdlib_Array.reduce(snapshots, 0, (acc, snapshot) => acc + select(snapshot) | 0);
|
|
40
|
+
let sumFloat = select => Stdlib_Array.reduce(snapshots, 0, (acc, snapshot) => acc + select(snapshot));
|
|
41
|
+
return {
|
|
42
|
+
startTime: startTime,
|
|
43
|
+
metricTime: metricTime,
|
|
44
|
+
elapsedSeconds: elapsedSeconds,
|
|
45
|
+
targetBufferSize: targetBufferSize,
|
|
46
|
+
isInReorgThreshold: Utils.$$Array.notEmpty(snapshots) && snapshots.every(s => s.isInReorgThreshold),
|
|
47
|
+
hasArrivedAtHead: Utils.$$Array.notEmpty(snapshots) && snapshots.every(s => s.hasArrivedAtHead),
|
|
48
|
+
rollbackEnabled: snapshots.some(s => s.rollbackEnabled),
|
|
49
|
+
maxBatchSize: Stdlib_Array.reduce(snapshots, 0, (acc, s) => Primitive_int.max(acc, s.maxBatchSize)),
|
|
50
|
+
preloadSeconds: sumFloat(s => s.preloadSeconds),
|
|
51
|
+
processingSeconds: sumFloat(s => s.processingSeconds),
|
|
52
|
+
processingStalledOnFetchSeconds: sumFloat(s => s.processingStalledOnFetchSeconds),
|
|
53
|
+
processingStalledOnStorageWriteSeconds: sumFloat(s => s.processingStalledOnStorageWriteSeconds),
|
|
54
|
+
rollbackSeconds: sumFloat(s => s.rollbackSeconds),
|
|
55
|
+
rollbackCount: sumInt(s => s.rollbackCount),
|
|
56
|
+
rollbackEventsCount: sumFloat(s => s.rollbackEventsCount),
|
|
57
|
+
chains: snapshots.flatMap(s => s.chains),
|
|
58
|
+
handlers: sumByKey(snapshots.flatMap(s => s.handlers), h => h.contract + `.` + h.event, (a, b) => ({
|
|
59
|
+
contract: a.contract,
|
|
60
|
+
event: a.event,
|
|
61
|
+
processingSeconds: a.processingSeconds + b.processingSeconds,
|
|
62
|
+
processingCount: a.processingCount + b.processingCount,
|
|
63
|
+
preloadSeconds: a.preloadSeconds + b.preloadSeconds,
|
|
64
|
+
preloadCount: a.preloadCount + b.preloadCount,
|
|
65
|
+
preloadSecondsTotal: a.preloadSecondsTotal + b.preloadSecondsTotal
|
|
66
|
+
})),
|
|
67
|
+
effects: sumByKey(snapshots.flatMap(s => s.effects), e => e.effect + `.` + e.scope, (a, b) => {
|
|
68
|
+
let match = a.cacheCount;
|
|
69
|
+
let match$1 = b.cacheCount;
|
|
70
|
+
return {
|
|
71
|
+
effect: a.effect,
|
|
72
|
+
scope: a.scope,
|
|
73
|
+
callSeconds: a.callSeconds + b.callSeconds,
|
|
74
|
+
callSecondsTotal: a.callSecondsTotal + b.callSecondsTotal,
|
|
75
|
+
callCount: a.callCount + b.callCount,
|
|
76
|
+
activeCallsCount: a.activeCallsCount + b.activeCallsCount | 0,
|
|
77
|
+
queueCount: a.queueCount + b.queueCount | 0,
|
|
78
|
+
queueWaitSeconds: a.queueWaitSeconds + b.queueWaitSeconds,
|
|
79
|
+
invalidationsCount: a.invalidationsCount + b.invalidationsCount,
|
|
80
|
+
cacheCount: match !== undefined ? (
|
|
81
|
+
match$1 !== undefined ? match + match$1 | 0 : match
|
|
82
|
+
) : match$1
|
|
83
|
+
};
|
|
84
|
+
}),
|
|
85
|
+
storageLoads: sumByKey(snapshots.flatMap(s => s.storageLoads), l => l.storage + `.` + l.operation, (a, b) => ({
|
|
86
|
+
operation: a.operation,
|
|
87
|
+
storage: a.storage,
|
|
88
|
+
seconds: a.seconds + b.seconds,
|
|
89
|
+
secondsTotal: a.secondsTotal + b.secondsTotal,
|
|
90
|
+
count: a.count + b.count,
|
|
91
|
+
whereSize: a.whereSize + b.whereSize,
|
|
92
|
+
size: a.size + b.size
|
|
93
|
+
})),
|
|
94
|
+
storageWrites: sumByKey(snapshots.flatMap(s => s.storageWrites), w => w.storage, (a, b) => ({
|
|
95
|
+
storage: a.storage,
|
|
96
|
+
seconds: a.seconds + b.seconds,
|
|
97
|
+
count: a.count + b.count | 0
|
|
98
|
+
})),
|
|
99
|
+
historyPrunes: sumByKey(snapshots.flatMap(s => s.historyPrunes), p => p.entity, (a, b) => ({
|
|
100
|
+
entity: a.entity,
|
|
101
|
+
seconds: a.seconds + b.seconds,
|
|
102
|
+
count: a.count + b.count | 0
|
|
103
|
+
})),
|
|
104
|
+
sourceRequests: snapshots.flatMap(s => s.sourceRequests),
|
|
105
|
+
sourceHeights: snapshots.flatMap(s => s.sourceHeights),
|
|
106
|
+
sourceHeightStreams: snapshots.flatMap(s => s.sourceHeightStreams)
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
21
110
|
function formatValue(value) {
|
|
22
111
|
return (Math.round(value * 1000) / 1000).toString();
|
|
23
112
|
}
|
|
@@ -365,24 +454,12 @@ function startRuntimeCollectors() {
|
|
|
365
454
|
getRuntimeCollectors();
|
|
366
455
|
}
|
|
367
456
|
|
|
368
|
-
function
|
|
369
|
-
let b = {
|
|
370
|
-
out: ""
|
|
371
|
-
};
|
|
457
|
+
function sampleRuntime() {
|
|
372
458
|
let memory = Process.memoryUsage();
|
|
373
459
|
let cpu = Process.cpuUsage();
|
|
374
460
|
let elu = Perf_hooks.performance.eventLoopUtilization();
|
|
375
461
|
let match = getRuntimeCollectors();
|
|
376
462
|
let eventLoopDelay = match.eventLoopDelay;
|
|
377
|
-
single(b, "process_cpu_user_seconds_total", "Total user CPU time spent in seconds.", "counter", cpu.user / 1000000);
|
|
378
|
-
single(b, "process_cpu_system_seconds_total", "Total system CPU time spent in seconds.", "counter", cpu.system / 1000000);
|
|
379
|
-
single(b, "process_cpu_seconds_total", "Total user and system CPU time spent in seconds.", "counter", (cpu.user + cpu.system) / 1000000);
|
|
380
|
-
single(b, "process_start_time_seconds", "Start time of the process since unix epoch in seconds.", "gauge", match.processStartTimeSeconds);
|
|
381
|
-
single(b, "process_resident_memory_bytes", "Resident memory size in bytes.", "gauge", memory.rss);
|
|
382
|
-
single(b, "nodejs_heap_size_total_bytes", "Process heap size from Node.js in bytes.", "gauge", memory.heapTotal);
|
|
383
|
-
single(b, "nodejs_heap_size_used_bytes", "Process heap size used from Node.js in bytes.", "gauge", memory.heapUsed);
|
|
384
|
-
single(b, "nodejs_external_memory_bytes", "Node.js external memory size in bytes.", "gauge", memory.external);
|
|
385
|
-
single(b, "nodejs_eventloop_utilization", "Ratio of time the event loop is active, since process start.", "gauge", elu.utilization);
|
|
386
463
|
let hasLagSamples = eventLoopDelay.max > 0;
|
|
387
464
|
let nsToSeconds = ns => {
|
|
388
465
|
if (hasLagSamples && !Number.isNaN(ns)) {
|
|
@@ -391,52 +468,152 @@ function collectRuntime() {
|
|
|
391
468
|
return 0;
|
|
392
469
|
}
|
|
393
470
|
};
|
|
394
|
-
single(b, "nodejs_eventloop_lag_mean_seconds", "The mean of the recorded event loop delays.", "gauge", nsToSeconds(eventLoopDelay.mean));
|
|
395
|
-
single(b, "nodejs_eventloop_lag_min_seconds", "The minimum recorded event loop delay.", "gauge", nsToSeconds(eventLoopDelay.min));
|
|
396
|
-
single(b, "nodejs_eventloop_lag_max_seconds", "The maximum recorded event loop delay.", "gauge", nsToSeconds(eventLoopDelay.max));
|
|
397
|
-
single(b, "nodejs_eventloop_lag_stddev_seconds", "The standard deviation of the recorded event loop delays.", "gauge", nsToSeconds(eventLoopDelay.stddev));
|
|
398
|
-
single(b, "nodejs_eventloop_lag_p50_seconds", "The 50th percentile of the recorded event loop delays.", "gauge", nsToSeconds(eventLoopDelay.percentile(50)));
|
|
399
|
-
single(b, "nodejs_eventloop_lag_p90_seconds", "The 90th percentile of the recorded event loop delays.", "gauge", nsToSeconds(eventLoopDelay.percentile(90)));
|
|
400
|
-
single(b, "nodejs_eventloop_lag_p99_seconds", "The 99th percentile of the recorded event loop delays.", "gauge", nsToSeconds(eventLoopDelay.percentile(99)));
|
|
401
|
-
eventLoopDelay.reset();
|
|
402
|
-
let heapSpaces = V8.getHeapSpaceStatistics().map(s => [
|
|
403
|
-
`{space="` + s.space_name.replace("_space", "") + `"}`,
|
|
404
|
-
s
|
|
405
|
-
]);
|
|
406
|
-
series(b, "nodejs_heap_space_size_total_bytes", "Process heap space size total from Node.js in bytes.", "gauge", heapSpaces, s => s.space_size);
|
|
407
|
-
series(b, "nodejs_heap_space_size_used_bytes", "Process heap space size used from Node.js in bytes.", "gauge", heapSpaces, s => s.space_used_size);
|
|
408
|
-
series(b, "nodejs_heap_space_size_available_bytes", "Process heap space size available from Node.js in bytes.", "gauge", heapSpaces, s => s.space_available_size);
|
|
409
471
|
let byType = {};
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
472
|
+
let sample_cpuUserSeconds = cpu.user / 1000000;
|
|
473
|
+
let sample_cpuSystemSeconds = cpu.system / 1000000;
|
|
474
|
+
let sample_processStartTimeSeconds = match.processStartTimeSeconds;
|
|
475
|
+
let sample_residentMemoryBytes = memory.rss;
|
|
476
|
+
let sample_heapTotalBytes = memory.heapTotal;
|
|
477
|
+
let sample_heapUsedBytes = memory.heapUsed;
|
|
478
|
+
let sample_externalMemoryBytes = memory.external;
|
|
479
|
+
let sample_eventLoopUtilization = elu.utilization;
|
|
480
|
+
let sample_eventLoopLagMeanSeconds = nsToSeconds(eventLoopDelay.mean);
|
|
481
|
+
let sample_eventLoopLagMinSeconds = nsToSeconds(eventLoopDelay.min);
|
|
482
|
+
let sample_eventLoopLagMaxSeconds = nsToSeconds(eventLoopDelay.max);
|
|
483
|
+
let sample_eventLoopLagStddevSeconds = nsToSeconds(eventLoopDelay.stddev);
|
|
484
|
+
let sample_eventLoopLagP50Seconds = nsToSeconds(eventLoopDelay.percentile(50));
|
|
485
|
+
let sample_eventLoopLagP90Seconds = nsToSeconds(eventLoopDelay.percentile(90));
|
|
486
|
+
let sample_eventLoopLagP99Seconds = nsToSeconds(eventLoopDelay.percentile(99));
|
|
487
|
+
let sample_heapSpaces = V8.getHeapSpaceStatistics().map(s => ({
|
|
488
|
+
space: s.space_name.replace("_space", ""),
|
|
489
|
+
size: s.space_size,
|
|
490
|
+
used: s.space_used_size,
|
|
491
|
+
available: s.space_available_size
|
|
492
|
+
}));
|
|
493
|
+
let sample_activeResources = (Process.getActiveResourcesInfo().forEach(resource => {
|
|
494
|
+
byType[resource] = Stdlib_Option.getOr(byType[resource], 0) + 1;
|
|
495
|
+
}), Object.entries(byType));
|
|
496
|
+
let sample_gc = Object.entries(match.gcStats).map(param => {
|
|
497
|
+
let stat = param[1];
|
|
498
|
+
return {
|
|
499
|
+
kind: param[0],
|
|
500
|
+
count: stat.count,
|
|
501
|
+
seconds: stat.seconds
|
|
502
|
+
};
|
|
413
503
|
});
|
|
414
|
-
let
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
504
|
+
let sample = {
|
|
505
|
+
cpuUserSeconds: sample_cpuUserSeconds,
|
|
506
|
+
cpuSystemSeconds: sample_cpuSystemSeconds,
|
|
507
|
+
processStartTimeSeconds: sample_processStartTimeSeconds,
|
|
508
|
+
residentMemoryBytes: sample_residentMemoryBytes,
|
|
509
|
+
heapTotalBytes: sample_heapTotalBytes,
|
|
510
|
+
heapUsedBytes: sample_heapUsedBytes,
|
|
511
|
+
externalMemoryBytes: sample_externalMemoryBytes,
|
|
512
|
+
eventLoopUtilization: sample_eventLoopUtilization,
|
|
513
|
+
eventLoopLagMeanSeconds: sample_eventLoopLagMeanSeconds,
|
|
514
|
+
eventLoopLagMinSeconds: sample_eventLoopLagMinSeconds,
|
|
515
|
+
eventLoopLagMaxSeconds: sample_eventLoopLagMaxSeconds,
|
|
516
|
+
eventLoopLagStddevSeconds: sample_eventLoopLagStddevSeconds,
|
|
517
|
+
eventLoopLagP50Seconds: sample_eventLoopLagP50Seconds,
|
|
518
|
+
eventLoopLagP90Seconds: sample_eventLoopLagP90Seconds,
|
|
519
|
+
eventLoopLagP99Seconds: sample_eventLoopLagP99Seconds,
|
|
520
|
+
heapSpaces: sample_heapSpaces,
|
|
521
|
+
activeResources: sample_activeResources,
|
|
522
|
+
gc: sample_gc,
|
|
523
|
+
nodeVersion: Process.version
|
|
524
|
+
};
|
|
525
|
+
eventLoopDelay.reset();
|
|
526
|
+
return sample;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function renderRuntime(samples) {
|
|
530
|
+
let b = {
|
|
531
|
+
out: ""
|
|
532
|
+
};
|
|
533
|
+
let labels = (scope, own) => {
|
|
534
|
+
if (scope === "") {
|
|
535
|
+
if (own === "") {
|
|
536
|
+
return "";
|
|
537
|
+
} else {
|
|
538
|
+
return `{` + own + `}`;
|
|
539
|
+
}
|
|
540
|
+
} else if (own === "") {
|
|
541
|
+
return `{` + scope + `}`;
|
|
542
|
+
} else {
|
|
543
|
+
return `{` + scope + `,` + own + `}`;
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
let scoped = samples.map(param => [
|
|
547
|
+
labels(param[0], ""),
|
|
548
|
+
param[1]
|
|
549
|
+
]);
|
|
550
|
+
let each = select => samples.flatMap(param => {
|
|
551
|
+
let scope = param[0];
|
|
552
|
+
return select(param[1]).map(param => [
|
|
553
|
+
labels(scope, param[0]),
|
|
554
|
+
param[1]
|
|
422
555
|
]);
|
|
423
556
|
});
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
557
|
+
let gauge = (name, help, value) => series(b, name, help, "gauge", scoped, value);
|
|
558
|
+
let counter = (name, help, value) => series(b, name, help, "counter", scoped, value);
|
|
559
|
+
counter("process_cpu_user_seconds_total", "Total user CPU time spent in seconds.", s => s.cpuUserSeconds);
|
|
560
|
+
counter("process_cpu_system_seconds_total", "Total system CPU time spent in seconds.", s => s.cpuSystemSeconds);
|
|
561
|
+
counter("process_cpu_seconds_total", "Total user and system CPU time spent in seconds.", s => s.cpuUserSeconds + s.cpuSystemSeconds);
|
|
562
|
+
gauge("process_start_time_seconds", "Start time of the process since unix epoch in seconds.", s => s.processStartTimeSeconds);
|
|
563
|
+
gauge("process_resident_memory_bytes", "Resident memory size in bytes.", s => s.residentMemoryBytes);
|
|
564
|
+
gauge("nodejs_heap_size_total_bytes", "Process heap size from Node.js in bytes.", s => s.heapTotalBytes);
|
|
565
|
+
gauge("nodejs_heap_size_used_bytes", "Process heap size used from Node.js in bytes.", s => s.heapUsedBytes);
|
|
566
|
+
gauge("nodejs_external_memory_bytes", "Node.js external memory size in bytes.", s => s.externalMemoryBytes);
|
|
567
|
+
gauge("nodejs_eventloop_utilization", "Ratio of time the event loop is active, since process start.", s => s.eventLoopUtilization);
|
|
568
|
+
gauge("nodejs_eventloop_lag_mean_seconds", "The mean of the recorded event loop delays.", s => s.eventLoopLagMeanSeconds);
|
|
569
|
+
gauge("nodejs_eventloop_lag_min_seconds", "The minimum recorded event loop delay.", s => s.eventLoopLagMinSeconds);
|
|
570
|
+
gauge("nodejs_eventloop_lag_max_seconds", "The maximum recorded event loop delay.", s => s.eventLoopLagMaxSeconds);
|
|
571
|
+
gauge("nodejs_eventloop_lag_stddev_seconds", "The standard deviation of the recorded event loop delays.", s => s.eventLoopLagStddevSeconds);
|
|
572
|
+
gauge("nodejs_eventloop_lag_p50_seconds", "The 50th percentile of the recorded event loop delays.", s => s.eventLoopLagP50Seconds);
|
|
573
|
+
gauge("nodejs_eventloop_lag_p90_seconds", "The 90th percentile of the recorded event loop delays.", s => s.eventLoopLagP90Seconds);
|
|
574
|
+
gauge("nodejs_eventloop_lag_p99_seconds", "The 99th percentile of the recorded event loop delays.", s => s.eventLoopLagP99Seconds);
|
|
575
|
+
let heapSpaces = each(s => s.heapSpaces.map(h => [
|
|
576
|
+
`space="` + h.space + `"`,
|
|
577
|
+
h
|
|
578
|
+
]));
|
|
579
|
+
series(b, "nodejs_heap_space_size_total_bytes", "Process heap space size total from Node.js in bytes.", "gauge", heapSpaces, h => h.size);
|
|
580
|
+
series(b, "nodejs_heap_space_size_used_bytes", "Process heap space size used from Node.js in bytes.", "gauge", heapSpaces, h => h.used);
|
|
581
|
+
series(b, "nodejs_heap_space_size_available_bytes", "Process heap space size available from Node.js in bytes.", "gauge", heapSpaces, h => h.available);
|
|
582
|
+
series(b, "nodejs_active_resources", "Number of active resources that are currently keeping the event loop alive, grouped by async resource type.", "gauge", each(s => s.activeResources.map(param => [
|
|
583
|
+
`type="` + escapeLabelValue(param[0]) + `"`,
|
|
584
|
+
param[1]
|
|
585
|
+
])), count => count);
|
|
586
|
+
gauge("nodejs_active_resources_total", "Total number of active resources.", s => Stdlib_Array.reduce(s.activeResources, 0, (acc, param) => acc + param[1]));
|
|
587
|
+
let gc = each(s => s.gc.map(g => [
|
|
588
|
+
`kind="` + g.kind + `"`,
|
|
589
|
+
g
|
|
590
|
+
]));
|
|
591
|
+
series(b, "nodejs_gc_duration_seconds_sum", "Cumulative garbage collection pause time by kind, one of major, minor, incremental or weakcb.", "counter", gc, g => g.seconds);
|
|
592
|
+
series(b, "nodejs_gc_duration_seconds_count", "Number of garbage collection pauses by kind, one of major, minor, incremental or weakcb.", "counter", gc, g => g.count);
|
|
593
|
+
series(b, "nodejs_version_info", "Node.js version info.", "gauge", each(s => {
|
|
594
|
+
let parts = s.nodeVersion.replace("v", "").split(".");
|
|
595
|
+
let part = i => Stdlib_Option.getOr(parts[i], "0");
|
|
596
|
+
return [[
|
|
597
|
+
`version="` + s.nodeVersion + `",major="` + part(0) + `",minor="` + part(1) + `",patch="` + part(2) + `"`,
|
|
598
|
+
undefined
|
|
599
|
+
]];
|
|
600
|
+
}), () => 1);
|
|
433
601
|
return b.out + "\n";
|
|
434
602
|
}
|
|
435
603
|
|
|
604
|
+
function collectRuntime() {
|
|
605
|
+
return renderRuntime([[
|
|
606
|
+
"",
|
|
607
|
+
sampleRuntime()
|
|
608
|
+
]]);
|
|
609
|
+
}
|
|
610
|
+
|
|
436
611
|
let contentType = "text/plain; version=0.0.4; charset=utf-8";
|
|
437
612
|
|
|
438
613
|
export {
|
|
439
614
|
hasProcessedToEndblock,
|
|
615
|
+
sumByKey,
|
|
616
|
+
merge,
|
|
440
617
|
formatValue,
|
|
441
618
|
escapeLabelValue,
|
|
442
619
|
block,
|
|
@@ -451,6 +628,8 @@ export {
|
|
|
451
628
|
runtimeCollectors,
|
|
452
629
|
getRuntimeCollectors,
|
|
453
630
|
startRuntimeCollectors,
|
|
631
|
+
sampleRuntime,
|
|
632
|
+
renderRuntime,
|
|
454
633
|
collectRuntime,
|
|
455
634
|
}
|
|
456
635
|
/* v8 Not a pure module */
|
package/src/Persistence.res
CHANGED
|
@@ -275,6 +275,10 @@ let init = {
|
|
|
275
275
|
// would create rows for this process's chains only, leaving the ones it
|
|
276
276
|
// skipped with no state for their own processes to resume.
|
|
277
277
|
~requireInitialized=false,
|
|
278
|
+
// Whether this process is the one that tells the operator the run resumed.
|
|
279
|
+
// A supervisor says it once for the whole run, so the workers it forked
|
|
280
|
+
// keep it to their own log files.
|
|
281
|
+
~announceResume=true,
|
|
278
282
|
~startBlockRetry=StartBlockResolver.UntilItAnswers,
|
|
279
283
|
) => {
|
|
280
284
|
try {
|
|
@@ -324,7 +328,8 @@ let init = {
|
|
|
324
328
|
| _ => false
|
|
325
329
|
}
|
|
326
330
|
) {
|
|
327
|
-
Logging.info
|
|
331
|
+
let logResume = announceResume ? Logging.info : Logging.trace
|
|
332
|
+
logResume(`Found existing indexer storage. Resuming indexing state...`)
|
|
328
333
|
let initialState = await persistence.storage.resumeInitialState(
|
|
329
334
|
~entities=persistence.allEntities,
|
|
330
335
|
~chainIds=chainConfigs->Array.map(chain => chain.id),
|
|
@@ -343,7 +348,7 @@ let init = {
|
|
|
343
348
|
initialState.chains->Array.forEach(c => {
|
|
344
349
|
progress->ChainId.Dict.set(c.id, c.progressBlockNumber)
|
|
345
350
|
})
|
|
346
|
-
|
|
351
|
+
logResume({
|
|
347
352
|
"msg": `Successfully resumed indexing state! Continuing from the last checkpoint.`,
|
|
348
353
|
"progress": progress,
|
|
349
354
|
})
|
|
@@ -356,6 +361,29 @@ let init = {
|
|
|
356
361
|
}
|
|
357
362
|
}
|
|
358
363
|
|
|
364
|
+
// Brings the schema up to date for a run that is about to start, as opposed to
|
|
365
|
+
// a migration command: what a config change prints names the command the
|
|
366
|
+
// operator ran, and an unreachable chain is waited on rather than reported,
|
|
367
|
+
// since somebody is watching the run come up.
|
|
368
|
+
let initForRun = (
|
|
369
|
+
persistence,
|
|
370
|
+
~config: Config.t,
|
|
371
|
+
~reset,
|
|
372
|
+
~isDevelopmentMode,
|
|
373
|
+
~requireInitialized,
|
|
374
|
+
) =>
|
|
375
|
+
persistence->init(
|
|
376
|
+
~announceResume=!Worker.isEnabled,
|
|
377
|
+
~reset,
|
|
378
|
+
~chainConfigs=config.chainMap->ChainMap.values,
|
|
379
|
+
~contractMapping=config.contractMapping,
|
|
380
|
+
~envioInfo=Config.envioInfo(),
|
|
381
|
+
~resetCommand=isDevelopmentMode ? "envio dev -r" : "envio start -r",
|
|
382
|
+
~runCommand=Some(isDevelopmentMode ? "envio dev" : "envio start"),
|
|
383
|
+
~lowercaseAddresses=config.lowercaseAddresses,
|
|
384
|
+
~requireInitialized,
|
|
385
|
+
)
|
|
386
|
+
|
|
359
387
|
let getInitializedStorageOrThrow = persistence => {
|
|
360
388
|
switch persistence.storageStatus {
|
|
361
389
|
| Unknown
|
package/src/Persistence.res.mjs
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Batch from "./Batch.res.mjs";
|
|
4
4
|
import * as Config from "./Config.res.mjs";
|
|
5
|
+
import * as Worker from "./Worker.res.mjs";
|
|
5
6
|
import * as Logging from "./Logging.res.mjs";
|
|
7
|
+
import * as ChainMap from "./ChainMap.res.mjs";
|
|
6
8
|
import * as Frontier from "./db/Frontier.res.mjs";
|
|
7
9
|
import * as EntityHistory from "./db/EntityHistory.res.mjs";
|
|
8
10
|
import * as ErrorHandling from "./ErrorHandling.res.mjs";
|
|
@@ -31,10 +33,11 @@ function make(userEntities, allEnums, storage) {
|
|
|
31
33
|
};
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
async function init(persistence, chainConfigs, contractMapping, envioInfo, resetCommand, runCommand, resetOpt, lowercaseAddressesOpt, requireInitializedOpt, startBlockRetryOpt) {
|
|
36
|
+
async function init(persistence, chainConfigs, contractMapping, envioInfo, resetCommand, runCommand, resetOpt, lowercaseAddressesOpt, requireInitializedOpt, announceResumeOpt, startBlockRetryOpt) {
|
|
35
37
|
let reset = resetOpt !== undefined ? resetOpt : false;
|
|
36
38
|
let lowercaseAddresses = lowercaseAddressesOpt !== undefined ? lowercaseAddressesOpt : false;
|
|
37
39
|
let requireInitialized = requireInitializedOpt !== undefined ? requireInitializedOpt : false;
|
|
40
|
+
let announceResume = announceResumeOpt !== undefined ? announceResumeOpt : true;
|
|
38
41
|
let startBlockRetry = startBlockRetryOpt !== undefined ? startBlockRetryOpt : "UntilItAnswers";
|
|
39
42
|
try {
|
|
40
43
|
let promise = persistence.storageStatus;
|
|
@@ -77,7 +80,8 @@ async function init(persistence, chainConfigs, contractMapping, envioInfo, reset
|
|
|
77
80
|
let tmp;
|
|
78
81
|
tmp = typeof match !== "object" ? false : match.TAG === "Initializing";
|
|
79
82
|
if (tmp) {
|
|
80
|
-
Logging.info
|
|
83
|
+
let logResume = announceResume ? Logging.info : Logging.trace;
|
|
84
|
+
logResume(`Found existing indexer storage. Resuming indexing state...`);
|
|
81
85
|
let initialState$1 = await persistence.storage.resumeInitialState(persistence.allEntities, chainConfigs.map(chain => chain.id), (storedEnvioInfo, storedContractMapping) => Config.throwIfResumeIncompatible(storedEnvioInfo, storedContractMapping, envioInfo, contractMapping, resetCommand, runCommand));
|
|
82
86
|
persistence.storageStatus = {
|
|
83
87
|
TAG: "Ready",
|
|
@@ -87,7 +91,7 @@ async function init(persistence, chainConfigs, contractMapping, envioInfo, reset
|
|
|
87
91
|
initialState$1.chains.forEach(c => {
|
|
88
92
|
progress[c.id] = c.progressBlockNumber;
|
|
89
93
|
});
|
|
90
|
-
|
|
94
|
+
logResume({
|
|
91
95
|
msg: `Successfully resumed indexing state! Continuing from the last checkpoint.`,
|
|
92
96
|
progress: progress
|
|
93
97
|
});
|
|
@@ -100,6 +104,10 @@ async function init(persistence, chainConfigs, contractMapping, envioInfo, reset
|
|
|
100
104
|
}
|
|
101
105
|
}
|
|
102
106
|
|
|
107
|
+
function initForRun(persistence, config, reset, isDevelopmentMode, requireInitialized) {
|
|
108
|
+
return init(persistence, ChainMap.values(config.chainMap), config.contractMapping, Config.envioInfo(), isDevelopmentMode ? "envio dev -r" : "envio start -r", isDevelopmentMode ? "envio dev" : "envio start", reset, config.lowercaseAddresses, requireInitialized, !Worker.isEnabled, undefined);
|
|
109
|
+
}
|
|
110
|
+
|
|
103
111
|
function getInitializedStorageOrThrow(persistence) {
|
|
104
112
|
let match = persistence.storageStatus;
|
|
105
113
|
if (typeof match !== "object" || match.TAG === "Initializing") {
|
|
@@ -123,6 +131,7 @@ export {
|
|
|
123
131
|
StorageError,
|
|
124
132
|
make,
|
|
125
133
|
init,
|
|
134
|
+
initForRun,
|
|
126
135
|
getInitializedStorageOrThrow,
|
|
127
136
|
getInitializedState,
|
|
128
137
|
}
|
package/src/PgStorage.res
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
let makeClient = () => {
|
|
1
|
+
let makeClient = (~maxConnections=Env.Db.maxConnections) => {
|
|
2
2
|
Postgres.makeSql(
|
|
3
3
|
~config={
|
|
4
4
|
host: Env.Db.host,
|
|
@@ -14,7 +14,7 @@ let makeClient = () => {
|
|
|
14
14
|
: Some(_str => ())
|
|
15
15
|
),
|
|
16
16
|
transform: {undefined: Null},
|
|
17
|
-
max:
|
|
17
|
+
max: maxConnections,
|
|
18
18
|
// debug: (~connection, ~query, ~params as _, ~types as _) => Js.log2(connection, query),
|
|
19
19
|
},
|
|
20
20
|
)
|
|
@@ -1857,7 +1857,7 @@ let make = (
|
|
|
1857
1857
|
if withUpload {
|
|
1858
1858
|
// Try to restore cache tables from the .envio/cache TSV files
|
|
1859
1859
|
switch await scanCacheDir() {
|
|
1860
|
-
| [] => Logging.info("No cache
|
|
1860
|
+
| [] => Logging.info("No saved effect cache to load from .envio/cache.")
|
|
1861
1861
|
| entries =>
|
|
1862
1862
|
switch await getConnectedPsqlExec(~pgUser, ~pgHost, ~pgDatabase, ~pgPort, ~containerName) {
|
|
1863
1863
|
| Ok(psqlExec) =>
|
|
@@ -2104,7 +2104,7 @@ let make = (
|
|
|
2104
2104
|
switch await sql->loadCatalogRows(~indexName=name) {
|
|
2105
2105
|
| rows => indexManager->IndexManager.resync(~name, ~rows)
|
|
2106
2106
|
| exception exn =>
|
|
2107
|
-
Logging.
|
|
2107
|
+
Logging.trace({
|
|
2108
2108
|
"storage": storageName,
|
|
2109
2109
|
"msg": `Could not re-read the index "${name}" after a failed build. The next attempt reads it again.`,
|
|
2110
2110
|
"err": exn->Utils.prettifyExn,
|
|
@@ -2264,13 +2264,17 @@ let make = (
|
|
|
2264
2264
|
}
|
|
2265
2265
|
|
|
2266
2266
|
switch missing {
|
|
2267
|
-
|
|
2267
|
+
// A schema that declares no indexes has nothing to say about them, and one
|
|
2268
|
+
// whose indexes are all in place says it once. Either way the line that
|
|
2269
|
+
// matters is the indexer reporting itself ready, which finalization logs.
|
|
2270
|
+
| [] if schemaIndexes->Utils.Array.notEmpty =>
|
|
2268
2271
|
Logging.info({
|
|
2269
2272
|
"storage": storageName,
|
|
2270
2273
|
"msg": `All ${schemaIndexes
|
|
2271
2274
|
->Array.length
|
|
2272
2275
|
->Int.toString} schema indexes are already in place. Marking the indexer ready.`,
|
|
2273
2276
|
})
|
|
2277
|
+
| [] => ()
|
|
2274
2278
|
| _ =>
|
|
2275
2279
|
Logging.info({
|
|
2276
2280
|
"storage": storageName,
|
|
@@ -2318,12 +2322,16 @@ let make = (
|
|
|
2318
2322
|
}
|
|
2319
2323
|
})
|
|
2320
2324
|
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2325
|
+
// Only when something was built: the wait this closes is the index build,
|
|
2326
|
+
// and the stamp on its own is not one anybody waited through.
|
|
2327
|
+
if missing->Utils.Array.notEmpty {
|
|
2328
|
+
Logging.info({
|
|
2329
|
+
"storage": storageName,
|
|
2330
|
+
"msg": `Committed ${missing
|
|
2331
|
+
->Array.length
|
|
2332
|
+
->Int.toString} schema indexes and the ready timestamp in ${timeRef->formatSeconds}s.`,
|
|
2333
|
+
})
|
|
2334
|
+
}
|
|
2327
2335
|
}
|
|
2328
2336
|
|
|
2329
2337
|
let setOrThrow = (
|
package/src/PgStorage.res.mjs
CHANGED
|
@@ -38,7 +38,8 @@ import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
|
38
38
|
import * as CheckpointSequence from "./db/CheckpointSequence.res.mjs";
|
|
39
39
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
40
40
|
|
|
41
|
-
function makeClient() {
|
|
41
|
+
function makeClient(maxConnectionsOpt) {
|
|
42
|
+
let maxConnections = maxConnectionsOpt !== undefined ? maxConnectionsOpt : Env.Db.maxConnections;
|
|
42
43
|
return Postgres({
|
|
43
44
|
host: Env.Db.host,
|
|
44
45
|
port: Env.Db.port,
|
|
@@ -46,7 +47,7 @@ function makeClient() {
|
|
|
46
47
|
username: Env.Db.user,
|
|
47
48
|
password: Env.Db.password,
|
|
48
49
|
ssl: Env.Db.ssl,
|
|
49
|
-
max:
|
|
50
|
+
max: maxConnections,
|
|
50
51
|
onnotice: Primitive_object.equal(Env.userLogLevel, "warn") || Primitive_object.equal(Env.userLogLevel, "error") ? undefined : _str => {},
|
|
51
52
|
transform: {
|
|
52
53
|
undefined: null
|
|
@@ -1182,7 +1183,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1182
1183
|
Logging.error(`Failed to upload cache, continuing without it. ` + psqlExec._0);
|
|
1183
1184
|
}
|
|
1184
1185
|
} else {
|
|
1185
|
-
Logging.info("No cache
|
|
1186
|
+
Logging.info("No saved effect cache to load from .envio/cache.");
|
|
1186
1187
|
}
|
|
1187
1188
|
}
|
|
1188
1189
|
let cacheTableInfo = await queryCacheTableInfo();
|
|
@@ -1310,7 +1311,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1310
1311
|
rows = await loadCatalogRows(sql, name);
|
|
1311
1312
|
} catch (raw_exn) {
|
|
1312
1313
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
1313
|
-
return Logging.
|
|
1314
|
+
return Logging.trace({
|
|
1314
1315
|
storage: storageName,
|
|
1315
1316
|
msg: `Could not re-read the index "` + name + `" after a failed build. The next attempt reads it again.`,
|
|
1316
1317
|
err: Utils.prettifyExn(exn)
|
|
@@ -1407,7 +1408,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1407
1408
|
msg: `Creating the ` + missing.length.toString() + ` remaining schema indexes before the indexer reports ready. Writes are paused until they are committed. ` + slowOnLargeDatabaseNotice,
|
|
1408
1409
|
indexes: missing.map(prepared => prepared.name)
|
|
1409
1410
|
});
|
|
1410
|
-
} else {
|
|
1411
|
+
} else if (Utils.$$Array.notEmpty(schemaIndexes)) {
|
|
1411
1412
|
Logging.info({
|
|
1412
1413
|
storage: storageName,
|
|
1413
1414
|
msg: `All ` + schemaIndexes.length.toString() + ` schema indexes are already in place. Marking the indexer ready.`
|
|
@@ -1438,10 +1439,12 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1438
1439
|
], {prepare: true});
|
|
1439
1440
|
}
|
|
1440
1441
|
});
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1442
|
+
if (Utils.$$Array.notEmpty(missing)) {
|
|
1443
|
+
return Logging.info({
|
|
1444
|
+
storage: storageName,
|
|
1445
|
+
msg: `Committed ` + missing.length.toString() + ` schema indexes and the ready timestamp in ` + formatSeconds(timeRef) + `s.`
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1445
1448
|
};
|
|
1446
1449
|
let setOrThrow$1 = (items, table, itemSchema) => setOrThrow(sql, items, table, itemSchema, pgSchema, setQueryCache, chainIdMode);
|
|
1447
1450
|
let setEffectCacheOrThrow = async (table, itemSchema, items, initialize) => {
|
|
@@ -1663,7 +1666,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
|
|
|
1663
1666
|
}
|
|
1664
1667
|
|
|
1665
1668
|
function makeStorageFromEnv(config, sqlOpt, pgSchemaOpt, isHasuraEnabledOpt) {
|
|
1666
|
-
let sql = sqlOpt !== undefined ? Primitive_option.valFromOption(sqlOpt) : makeClient();
|
|
1669
|
+
let sql = sqlOpt !== undefined ? Primitive_option.valFromOption(sqlOpt) : makeClient(undefined);
|
|
1667
1670
|
let pgSchema = pgSchemaOpt !== undefined ? pgSchemaOpt : Env.Db.publicSchema;
|
|
1668
1671
|
let isHasuraEnabled = isHasuraEnabledOpt !== undefined ? isHasuraEnabledOpt : Env.Hasura.enabled;
|
|
1669
1672
|
let tmp;
|
package/src/Rollback.res
CHANGED
|
@@ -11,9 +11,9 @@ let getLastKnownValidBlock = async (
|
|
|
11
11
|
~isRealtime: bool,
|
|
12
12
|
) => {
|
|
13
13
|
// Before the search, not after: it re-fetches the scanned hashes through the
|
|
14
|
-
// sources, and a
|
|
15
|
-
// chain would confirm blocks that no longer exist
|
|
16
|
-
// short of the real fork.
|
|
14
|
+
// sources, and a read still in flight from before the reorg describes the
|
|
15
|
+
// orphaned chain — joining one would confirm blocks that no longer exist and
|
|
16
|
+
// stop the rollback short of the real fork.
|
|
17
17
|
chainState->ChainState.sourceManager->SourceManager.onReorg
|
|
18
18
|
|
|
19
19
|
// Don't include the reorg block itself - different source instances
|