envio 3.3.0-rc.0 → 3.3.1-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 -7
- package/src/ChainFetching.res +4 -32
- package/src/ChainFetching.res.mjs +2 -12
- package/src/ChainState.res +73 -53
- package/src/ChainState.res.mjs +61 -30
- package/src/ChainState.resi +13 -17
- package/src/Config.res +5 -0
- package/src/Config.res.mjs +1 -0
- package/src/CrossChainState.res +4 -10
- package/src/CrossChainState.res.mjs +7 -9
- package/src/CrossChainState.resi +1 -0
- package/src/EffectState.res +183 -44
- package/src/EffectState.res.mjs +134 -26
- package/src/EffectState.resi +26 -3
- package/src/EventProcessing.res +14 -9
- package/src/EventProcessing.res.mjs +7 -7
- package/src/FetchState.res +18 -29
- package/src/FetchState.res.mjs +20 -37
- package/src/IndexerState.res +280 -31
- package/src/IndexerState.res.mjs +234 -25
- package/src/IndexerState.resi +22 -0
- package/src/LoadLayer.res +19 -65
- package/src/LoadLayer.res.mjs +13 -55
- package/src/Main.res +42 -23
- package/src/Main.res.mjs +32 -35
- package/src/Metrics.res +943 -66
- package/src/Metrics.res.mjs +367 -50
- package/src/Persistence.res +3 -0
- package/src/PgStorage.res +3 -8
- package/src/PgStorage.res.mjs +3 -4
- package/src/PruneStaleHistory.res +1 -1
- package/src/PruneStaleHistory.res.mjs +1 -2
- package/src/Rollback.res +4 -5
- package/src/Rollback.res.mjs +2 -3
- package/src/SimulateItems.res.mjs +3 -21
- package/src/TestIndexer.res.mjs +4 -23
- package/src/TestIndexerProxyStorage.res +1 -0
- package/src/TestIndexerProxyStorage.res.mjs +1 -1
- package/src/Writing.res +3 -5
- package/src/Writing.res.mjs +3 -6
- package/src/bindings/ClickHouse.res +101 -17
- package/src/bindings/ClickHouse.res.mjs +58 -19
- package/src/bindings/NodeJs.res +64 -0
- package/src/bindings/NodeJs.res.mjs +6 -0
- package/src/sources/HyperSyncClient.res +5 -11
- package/src/sources/SourceManager.res +72 -27
- package/src/sources/SourceManager.res.mjs +81 -11
- package/src/sources/SourceManager.resi +14 -0
- package/src/tui/Tui.res +1 -1
- package/src/tui/Tui.res.mjs +2 -2
- package/src/Prometheus.res +0 -789
- package/src/Prometheus.res.mjs +0 -847
- package/src/bindings/PromClient.res +0 -72
- package/src/bindings/PromClient.res.mjs +0 -38
package/src/IndexerState.res.mjs
CHANGED
|
@@ -8,11 +8,12 @@ import * as ChainMap from "./ChainMap.res.mjs";
|
|
|
8
8
|
import * as Internal from "./Internal.res.mjs";
|
|
9
9
|
import * as Throttler from "./Throttler.res.mjs";
|
|
10
10
|
import * as ChainState from "./ChainState.res.mjs";
|
|
11
|
-
import * as Prometheus from "./Prometheus.res.mjs";
|
|
12
11
|
import * as EffectState from "./EffectState.res.mjs";
|
|
13
12
|
import * as LoadManager from "./LoadManager.res.mjs";
|
|
13
|
+
import * as Performance from "./bindings/Performance.res.mjs";
|
|
14
14
|
import * as ErrorHandling from "./ErrorHandling.res.mjs";
|
|
15
15
|
import * as InMemoryTable from "./InMemoryTable.res.mjs";
|
|
16
|
+
import * as SourceManager from "./sources/SourceManager.res.mjs";
|
|
16
17
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
17
18
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
18
19
|
import * as CrossChainState from "./CrossChainState.res.mjs";
|
|
@@ -82,7 +83,16 @@ function make$1(config, persistence, chainStates, isInReorgThreshold, isRealtime
|
|
|
82
83
|
onError: onError,
|
|
83
84
|
isStopped: false,
|
|
84
85
|
epoch: 0,
|
|
85
|
-
simulateDeadInputTracker: SimulateDeadInputTracker.makeFromConfig(config)
|
|
86
|
+
simulateDeadInputTracker: SimulateDeadInputTracker.makeFromConfig(config),
|
|
87
|
+
preloadSeconds: 0,
|
|
88
|
+
processingSeconds: 0,
|
|
89
|
+
handlerStats: {},
|
|
90
|
+
storageLoadStats: {},
|
|
91
|
+
storageWriteStats: {},
|
|
92
|
+
historyPruneStats: {},
|
|
93
|
+
rollbackSeconds: 0,
|
|
94
|
+
rollbackCount: 0,
|
|
95
|
+
rollbackEventsCount: 0
|
|
86
96
|
};
|
|
87
97
|
}
|
|
88
98
|
|
|
@@ -101,12 +111,6 @@ function makeFromDbState(config, persistence, initialState, registrationsByChain
|
|
|
101
111
|
return false;
|
|
102
112
|
}
|
|
103
113
|
});
|
|
104
|
-
Prometheus.ProcessingMaxBatchSize.set(config.batchSize);
|
|
105
|
-
Prometheus.ReorgThreshold.set(isInReorgThreshold);
|
|
106
|
-
Utils.Dict.forEach(initialState.cache, param => {
|
|
107
|
-
let count = param.count;
|
|
108
|
-
Prometheus.EffectCacheCount.set(count, param.effectName, Internal.EffectCache.scopeToString(param.scope));
|
|
109
|
-
});
|
|
110
114
|
let isRealtime = !Env.updateSyncTimeOnRestart && initialState.chains.length !== 0 && initialState.chains.every(c => Stdlib_Option.isSome(c.timestampCaughtUpToHeadOrEndblock));
|
|
111
115
|
let chainStates = {};
|
|
112
116
|
initialState.chains.forEach(resumedChainState => {
|
|
@@ -114,24 +118,12 @@ function makeFromDbState(config, persistence, initialState, registrationsByChain
|
|
|
114
118
|
let chainConfig = ChainMap.get(config.chainMap, chain);
|
|
115
119
|
chainStates[resumedChainState.id] = ChainState.makeFromDbState(chainConfig, resumedChainState, initialState.reorgCheckpoints, isInReorgThreshold, isRealtime, config, registrationsByChainId, reducedPollingInterval);
|
|
116
120
|
});
|
|
117
|
-
let
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
let chainId = ChainState.chainConfig(cs).id;
|
|
122
|
-
Prometheus.ProgressBlockNumber.set(ChainState.committedProgressBlockNumber(cs), chainId);
|
|
123
|
-
Prometheus.ProgressReady.init(chainId);
|
|
124
|
-
if (ChainState.isReady(cs)) {
|
|
125
|
-
return Prometheus.ProgressReady.set(chainId);
|
|
126
|
-
} else {
|
|
127
|
-
allChainsReady.contents = false;
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
121
|
+
let state = make$1(config, persistence, chainStates, isInReorgThreshold, isRealtime, targetBufferSize, initialState.checkpointId, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, onError);
|
|
122
|
+
Utils.Dict.forEach(initialState.cache, param => {
|
|
123
|
+
let count = param.count;
|
|
124
|
+
EffectState.setUnregisteredCacheCount(state.effectState, param.effectName, param.scope, count);
|
|
130
125
|
});
|
|
131
|
-
|
|
132
|
-
Prometheus.ProgressReady.setAllReady();
|
|
133
|
-
}
|
|
134
|
-
return make$1(config, persistence, chainStates, isInReorgThreshold, isRealtime, targetBufferSize, initialState.checkpointId, isDevelopmentMode, shouldUseTui, exitAfterFirstEventBlock, onError);
|
|
126
|
+
return state;
|
|
135
127
|
}
|
|
136
128
|
|
|
137
129
|
function isStale(state, stateId) {
|
|
@@ -343,6 +335,213 @@ function simulateDeadInputTracker(state) {
|
|
|
343
335
|
return state.simulateDeadInputTracker;
|
|
344
336
|
}
|
|
345
337
|
|
|
338
|
+
function toMetrics(state) {
|
|
339
|
+
let chainStates = CrossChainState.chainStates(state.crossChainState);
|
|
340
|
+
let sourceRequests = [];
|
|
341
|
+
let sourceHeights = [];
|
|
342
|
+
Utils.Dict.forEach(chainStates, cs => {
|
|
343
|
+
let sourceManager = ChainState.sourceManager(cs);
|
|
344
|
+
SourceManager.getRequestStatSamples(sourceManager).forEach(s => {
|
|
345
|
+
sourceRequests.push({
|
|
346
|
+
source: s.sourceName,
|
|
347
|
+
chainId: s.chainId,
|
|
348
|
+
method: s.method,
|
|
349
|
+
count: s.count,
|
|
350
|
+
seconds: s.seconds
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
SourceManager.getSourceHeightSamples(sourceManager).forEach(s => {
|
|
354
|
+
sourceHeights.push({
|
|
355
|
+
source: s.sourceName,
|
|
356
|
+
chainId: s.chainId,
|
|
357
|
+
height: s.height
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
let historyPrunes = [];
|
|
362
|
+
Utils.Dict.forEachWithKey(state.historyPruneStats, (s, entityName) => {
|
|
363
|
+
historyPrunes.push({
|
|
364
|
+
entity: entityName,
|
|
365
|
+
seconds: s.seconds,
|
|
366
|
+
count: s.count
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
return {
|
|
370
|
+
startTime: state.indexerStartTime,
|
|
371
|
+
targetBufferSize: CrossChainState.targetBufferSize(state.crossChainState),
|
|
372
|
+
isInReorgThreshold: CrossChainState.isInReorgThreshold(state.crossChainState),
|
|
373
|
+
rollbackEnabled: state.config.shouldRollbackOnReorg,
|
|
374
|
+
maxBatchSize: state.config.batchSize,
|
|
375
|
+
preloadSeconds: state.preloadSeconds,
|
|
376
|
+
processingSeconds: state.processingSeconds,
|
|
377
|
+
rollbackSeconds: state.rollbackSeconds,
|
|
378
|
+
rollbackCount: state.rollbackCount,
|
|
379
|
+
rollbackEventsCount: state.rollbackEventsCount,
|
|
380
|
+
chains: Object.values(chainStates).map(ChainState.toMetrics),
|
|
381
|
+
handlers: Object.values(state.handlerStats).map(s => ({
|
|
382
|
+
contract: s.contract,
|
|
383
|
+
event: s.event,
|
|
384
|
+
processingSeconds: s.processingSeconds,
|
|
385
|
+
processingCount: s.processingCount,
|
|
386
|
+
preloadSeconds: s.preloadSeconds,
|
|
387
|
+
preloadCount: s.preloadCount,
|
|
388
|
+
preloadSecondsTotal: s.preloadSecondsTotal
|
|
389
|
+
})),
|
|
390
|
+
effects: EffectState.toMetrics(state.effectState),
|
|
391
|
+
storageLoads: Object.values(state.storageLoadStats).map(s => ({
|
|
392
|
+
operation: s.operation,
|
|
393
|
+
storage: s.storage,
|
|
394
|
+
seconds: s.seconds,
|
|
395
|
+
secondsTotal: s.secondsTotal,
|
|
396
|
+
count: s.count,
|
|
397
|
+
whereSize: s.whereSize,
|
|
398
|
+
size: s.size
|
|
399
|
+
})),
|
|
400
|
+
storageWrites: Object.values(state.storageWriteStats).map(s => ({
|
|
401
|
+
storage: s.storage,
|
|
402
|
+
seconds: s.seconds,
|
|
403
|
+
count: s.count
|
|
404
|
+
})),
|
|
405
|
+
historyPrunes: historyPrunes,
|
|
406
|
+
sourceRequests: sourceRequests,
|
|
407
|
+
sourceHeights: sourceHeights
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function recordBatchDurations(state, loadDuration, handlerDuration) {
|
|
412
|
+
state.preloadSeconds = state.preloadSeconds + loadDuration;
|
|
413
|
+
state.processingSeconds = state.processingSeconds + handlerDuration;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function getHandlerStat(state, contract, event) {
|
|
417
|
+
let key = contract.length.toString() + ":" + contract + event;
|
|
418
|
+
let stat = state.handlerStats[key];
|
|
419
|
+
if (stat !== undefined) {
|
|
420
|
+
return stat;
|
|
421
|
+
}
|
|
422
|
+
let stat$1 = {
|
|
423
|
+
contract: contract,
|
|
424
|
+
event: event,
|
|
425
|
+
processingSeconds: 0,
|
|
426
|
+
processingCount: 0,
|
|
427
|
+
preloadSeconds: 0,
|
|
428
|
+
preloadCount: 0,
|
|
429
|
+
preloadSecondsTotal: 0,
|
|
430
|
+
preloadPendingCount: 0,
|
|
431
|
+
preloadPendingTimerRef: null
|
|
432
|
+
};
|
|
433
|
+
state.handlerStats[key] = stat$1;
|
|
434
|
+
return stat$1;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function recordHandlerDuration(state, contract, event, duration) {
|
|
438
|
+
let stat = getHandlerStat(state, contract, event);
|
|
439
|
+
stat.processingSeconds = stat.processingSeconds + duration;
|
|
440
|
+
stat.processingCount = stat.processingCount + 1;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function startPreloadHandler(state, contract, event) {
|
|
444
|
+
let stat = getHandlerStat(state, contract, event);
|
|
445
|
+
if (stat.preloadPendingCount === 0) {
|
|
446
|
+
stat.preloadPendingTimerRef = Performance.now();
|
|
447
|
+
}
|
|
448
|
+
stat.preloadPendingCount = stat.preloadPendingCount + 1 | 0;
|
|
449
|
+
return Performance.now();
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function endPreloadHandler(state, timerRef, contract, event) {
|
|
453
|
+
let stat = getHandlerStat(state, contract, event);
|
|
454
|
+
stat.preloadPendingCount = stat.preloadPendingCount - 1 | 0;
|
|
455
|
+
if (stat.preloadPendingCount === 0) {
|
|
456
|
+
stat.preloadSeconds = stat.preloadSeconds + Performance.secondsSince(stat.preloadPendingTimerRef);
|
|
457
|
+
}
|
|
458
|
+
stat.preloadSecondsTotal = stat.preloadSecondsTotal + Performance.secondsSince(timerRef);
|
|
459
|
+
stat.preloadCount = stat.preloadCount + 1;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function getStorageLoadStat(state, storage, operation) {
|
|
463
|
+
let key = storage.length.toString() + ":" + storage + operation;
|
|
464
|
+
let stat = state.storageLoadStats[key];
|
|
465
|
+
if (stat !== undefined) {
|
|
466
|
+
return stat;
|
|
467
|
+
}
|
|
468
|
+
let stat$1 = {
|
|
469
|
+
operation: operation,
|
|
470
|
+
storage: storage,
|
|
471
|
+
seconds: 0,
|
|
472
|
+
secondsTotal: 0,
|
|
473
|
+
count: 0,
|
|
474
|
+
whereSize: 0,
|
|
475
|
+
size: 0,
|
|
476
|
+
pendingCount: 0,
|
|
477
|
+
pendingTimerRef: null
|
|
478
|
+
};
|
|
479
|
+
state.storageLoadStats[key] = stat$1;
|
|
480
|
+
return stat$1;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function startStorageLoad(state, storage, operation) {
|
|
484
|
+
let stat = getStorageLoadStat(state, storage, operation);
|
|
485
|
+
if (stat.pendingCount === 0) {
|
|
486
|
+
stat.pendingTimerRef = Performance.now();
|
|
487
|
+
}
|
|
488
|
+
stat.pendingCount = stat.pendingCount + 1 | 0;
|
|
489
|
+
return Performance.now();
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function endStorageLoad(state, timerRef, storage, operation, whereSize, size) {
|
|
493
|
+
let stat = getStorageLoadStat(state, storage, operation);
|
|
494
|
+
stat.pendingCount = stat.pendingCount - 1 | 0;
|
|
495
|
+
if (stat.pendingCount === 0) {
|
|
496
|
+
stat.seconds = stat.seconds + Performance.secondsSince(stat.pendingTimerRef);
|
|
497
|
+
}
|
|
498
|
+
stat.secondsTotal = stat.secondsTotal + Performance.secondsSince(timerRef);
|
|
499
|
+
stat.count = stat.count + 1;
|
|
500
|
+
stat.whereSize = stat.whereSize + whereSize;
|
|
501
|
+
stat.size = stat.size + size;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function recordStorageWrite(state, storage, timeSeconds) {
|
|
505
|
+
let stat = state.storageWriteStats[storage];
|
|
506
|
+
let stat$1;
|
|
507
|
+
if (stat !== undefined) {
|
|
508
|
+
stat$1 = stat;
|
|
509
|
+
} else {
|
|
510
|
+
let stat$2 = {
|
|
511
|
+
storage: storage,
|
|
512
|
+
seconds: 0,
|
|
513
|
+
count: 0
|
|
514
|
+
};
|
|
515
|
+
state.storageWriteStats[storage] = stat$2;
|
|
516
|
+
stat$1 = stat$2;
|
|
517
|
+
}
|
|
518
|
+
stat$1.seconds = stat$1.seconds + timeSeconds;
|
|
519
|
+
stat$1.count = stat$1.count + 1 | 0;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function recordHistoryPrune(state, entityName, timeSeconds) {
|
|
523
|
+
let stat = state.historyPruneStats[entityName];
|
|
524
|
+
let stat$1;
|
|
525
|
+
if (stat !== undefined) {
|
|
526
|
+
stat$1 = stat;
|
|
527
|
+
} else {
|
|
528
|
+
let stat$2 = {
|
|
529
|
+
seconds: 0,
|
|
530
|
+
count: 0
|
|
531
|
+
};
|
|
532
|
+
state.historyPruneStats[entityName] = stat$2;
|
|
533
|
+
stat$1 = stat$2;
|
|
534
|
+
}
|
|
535
|
+
stat$1.seconds = stat$1.seconds + timeSeconds;
|
|
536
|
+
stat$1.count = stat$1.count + 1 | 0;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function recordRollbackSuccess(state, timeSeconds, rollbackedProcessedEvents) {
|
|
540
|
+
state.rollbackSeconds = state.rollbackSeconds + timeSeconds;
|
|
541
|
+
state.rollbackCount = state.rollbackCount + 1 | 0;
|
|
542
|
+
state.rollbackEventsCount = state.rollbackEventsCount + rollbackedProcessedEvents;
|
|
543
|
+
}
|
|
544
|
+
|
|
346
545
|
function queueProcessedBatch(state, batch) {
|
|
347
546
|
state.processedBatches.push(batch);
|
|
348
547
|
let checkpointId = Utils.$$Array.last(batch.checkpointIds);
|
|
@@ -523,6 +722,16 @@ export {
|
|
|
523
722
|
epoch,
|
|
524
723
|
lastPrunedAtMillis,
|
|
525
724
|
simulateDeadInputTracker,
|
|
725
|
+
toMetrics,
|
|
726
|
+
recordBatchDurations,
|
|
727
|
+
recordHandlerDuration,
|
|
728
|
+
startPreloadHandler,
|
|
729
|
+
endPreloadHandler,
|
|
730
|
+
startStorageLoad,
|
|
731
|
+
endStorageLoad,
|
|
732
|
+
recordStorageWrite,
|
|
733
|
+
recordHistoryPrune,
|
|
734
|
+
recordRollbackSuccess,
|
|
526
735
|
queueProcessedBatch,
|
|
527
736
|
drainBatchRun,
|
|
528
737
|
takeRollback,
|
package/src/IndexerState.resi
CHANGED
|
@@ -101,6 +101,28 @@ let epoch: t => int
|
|
|
101
101
|
let lastPrunedAtMillis: t => dict<float>
|
|
102
102
|
let simulateDeadInputTracker: t => option<SimulateDeadInputTracker.t>
|
|
103
103
|
|
|
104
|
+
// Read-only snapshot of every metric; the single window into the mutable
|
|
105
|
+
// counters for the /metrics endpoint, the TUI and the console API.
|
|
106
|
+
let toMetrics: t => Metrics.t
|
|
107
|
+
|
|
108
|
+
// Metric counters.
|
|
109
|
+
let recordBatchDurations: (t, ~loadDuration: float, ~handlerDuration: float) => unit
|
|
110
|
+
let recordHandlerDuration: (t, ~contract: string, ~event: string, ~duration: float) => unit
|
|
111
|
+
let startPreloadHandler: (t, ~contract: string, ~event: string) => Performance.timeRef
|
|
112
|
+
let endPreloadHandler: (t, Performance.timeRef, ~contract: string, ~event: string) => unit
|
|
113
|
+
let startStorageLoad: (t, ~storage: string, ~operation: string) => Performance.timeRef
|
|
114
|
+
let endStorageLoad: (
|
|
115
|
+
t,
|
|
116
|
+
Performance.timeRef,
|
|
117
|
+
~storage: string,
|
|
118
|
+
~operation: string,
|
|
119
|
+
~whereSize: int,
|
|
120
|
+
~size: int,
|
|
121
|
+
) => unit
|
|
122
|
+
let recordStorageWrite: (t, ~storage: string, ~timeSeconds: float) => unit
|
|
123
|
+
let recordHistoryPrune: (t, ~entityName: string, ~timeSeconds: float) => unit
|
|
124
|
+
let recordRollbackSuccess: (t, ~timeSeconds: float, ~rollbackedProcessedEvents: float) => unit
|
|
125
|
+
|
|
104
126
|
// Store domain operations.
|
|
105
127
|
let queueProcessedBatch: (t, ~batch: Batch.t) => unit
|
|
106
128
|
let drainBatchRun: t => Batch.t
|
package/src/LoadLayer.res
CHANGED
|
@@ -13,7 +13,8 @@ let loadById = (
|
|
|
13
13
|
|
|
14
14
|
let load = async (idsToLoad, ~onError as _) => {
|
|
15
15
|
let storage = persistence->Persistence.getInitializedStorageOrThrow
|
|
16
|
-
let timerRef =
|
|
16
|
+
let timerRef =
|
|
17
|
+
indexerState->IndexerState.startStorageLoad(~storage=storage.name, ~operation=key)
|
|
17
18
|
|
|
18
19
|
// Since LoadManager.call prevents registering entities already in the in-memory store,
|
|
19
20
|
// we can be sure that we load only the new ones.
|
|
@@ -50,7 +51,8 @@ let loadById = (
|
|
|
50
51
|
)
|
|
51
52
|
})
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
indexerState->IndexerState.endStorageLoad(
|
|
55
|
+
timerRef,
|
|
54
56
|
~storage=storage.name,
|
|
55
57
|
~operation=key,
|
|
56
58
|
~whereSize=idsToLoad->Array.length,
|
|
@@ -76,25 +78,7 @@ let callEffect = (
|
|
|
76
78
|
~timerRef,
|
|
77
79
|
~onError,
|
|
78
80
|
) => {
|
|
79
|
-
|
|
80
|
-
let scopeLabel = inMemTable.scope->Internal.EffectCache.scopeToString
|
|
81
|
-
let hadActiveCalls = inMemTable.activeCallsCount > 0
|
|
82
|
-
inMemTable.activeCallsCount = inMemTable.activeCallsCount + 1
|
|
83
|
-
Prometheus.EffectCalls.activeCallsCount->Prometheus.SafeGauge.handleInt(
|
|
84
|
-
~labels={"effect": effectName, "scope": scopeLabel},
|
|
85
|
-
~value=inMemTable.activeCallsCount,
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
if hadActiveCalls {
|
|
89
|
-
let elapsed = Performance.secondsBetween(~from=inMemTable.prevCallStartTimerRef, ~to=timerRef)
|
|
90
|
-
if elapsed > 0. {
|
|
91
|
-
Prometheus.EffectCalls.timeCounter->Prometheus.SafeCounter.handleFloat(
|
|
92
|
-
~labels={"effect": effectName, "scope": scopeLabel},
|
|
93
|
-
~value=elapsed,
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
inMemTable.prevCallStartTimerRef = timerRef
|
|
81
|
+
inMemTable.stats->EffectState.startCall(~timerRef)
|
|
98
82
|
|
|
99
83
|
effect.handler(arg)
|
|
100
84
|
->Promise.thenResolve(output => {
|
|
@@ -109,25 +93,7 @@ let callEffect = (
|
|
|
109
93
|
onError(~inputKey=arg.cacheKey, ~exn)
|
|
110
94
|
})
|
|
111
95
|
->Promise.finally(() => {
|
|
112
|
-
inMemTable.
|
|
113
|
-
Prometheus.EffectCalls.activeCallsCount->Prometheus.SafeGauge.handleInt(
|
|
114
|
-
~labels={"effect": effectName, "scope": scopeLabel},
|
|
115
|
-
~value=inMemTable.activeCallsCount,
|
|
116
|
-
)
|
|
117
|
-
let newTimer = Performance.now()
|
|
118
|
-
Prometheus.EffectCalls.timeCounter->Prometheus.SafeCounter.handleFloat(
|
|
119
|
-
~labels={"effect": effectName, "scope": scopeLabel},
|
|
120
|
-
~value=Performance.secondsBetween(~from=inMemTable.prevCallStartTimerRef, ~to=newTimer),
|
|
121
|
-
)
|
|
122
|
-
inMemTable.prevCallStartTimerRef = newTimer
|
|
123
|
-
|
|
124
|
-
Prometheus.EffectCalls.totalCallsCount->Prometheus.SafeCounter.increment(
|
|
125
|
-
~labels={"effect": effectName, "scope": scopeLabel},
|
|
126
|
-
)
|
|
127
|
-
Prometheus.EffectCalls.sumTimeCounter->Prometheus.SafeCounter.handleFloat(
|
|
128
|
-
~labels={"effect": effectName, "scope": scopeLabel},
|
|
129
|
-
~value=timerRef->Performance.secondsSince,
|
|
130
|
-
)
|
|
96
|
+
inMemTable.stats->EffectState.endCall(~startTimerRef=timerRef)
|
|
131
97
|
})
|
|
132
98
|
}
|
|
133
99
|
|
|
@@ -138,8 +104,6 @@ let rec executeWithRateLimit = (
|
|
|
138
104
|
~onError,
|
|
139
105
|
~isFromQueue: bool,
|
|
140
106
|
) => {
|
|
141
|
-
let effectName = effect.name
|
|
142
|
-
|
|
143
107
|
let timerRef = Performance.now()
|
|
144
108
|
let promises = []
|
|
145
109
|
|
|
@@ -194,25 +158,13 @@ let rec executeWithRateLimit = (
|
|
|
194
158
|
}
|
|
195
159
|
|
|
196
160
|
if immediateCount > 0 && isFromQueue {
|
|
197
|
-
|
|
198
|
-
state.queueCount = state.queueCount - immediateCount
|
|
199
|
-
Prometheus.EffectQueueCount.set(
|
|
200
|
-
~count=state.queueCount,
|
|
201
|
-
~effectName,
|
|
202
|
-
~scope=inMemTable.scope->Internal.EffectCache.scopeToString,
|
|
203
|
-
)
|
|
161
|
+
inMemTable.stats->EffectState.queueDequeued(~count=immediateCount)
|
|
204
162
|
}
|
|
205
163
|
|
|
206
164
|
// Handle queued items
|
|
207
165
|
if queuedArgs->Utils.Array.notEmpty {
|
|
208
166
|
if !isFromQueue {
|
|
209
|
-
|
|
210
|
-
state.queueCount = state.queueCount + queuedArgs->Array.length
|
|
211
|
-
Prometheus.EffectQueueCount.set(
|
|
212
|
-
~count=state.queueCount,
|
|
213
|
-
~effectName,
|
|
214
|
-
~scope=inMemTable.scope->Internal.EffectCache.scopeToString,
|
|
215
|
-
)
|
|
167
|
+
inMemTable.stats->EffectState.queueEnqueued(~count=queuedArgs->Array.length)
|
|
216
168
|
}
|
|
217
169
|
|
|
218
170
|
let millisUntilReset = ref(0)
|
|
@@ -232,9 +184,8 @@ let rec executeWithRateLimit = (
|
|
|
232
184
|
nextWindowPromise
|
|
233
185
|
->Promise.then(() => {
|
|
234
186
|
if millisUntilReset.contents > 0 {
|
|
235
|
-
|
|
236
|
-
~
|
|
237
|
-
~value=millisUntilReset.contents->Int.toFloat /. 1000.,
|
|
187
|
+
inMemTable.stats->EffectState.addQueueWaitSeconds(
|
|
188
|
+
~seconds=millisUntilReset.contents->Int.toFloat /. 1000.,
|
|
238
189
|
)
|
|
239
190
|
}
|
|
240
191
|
executeWithRateLimit(
|
|
@@ -289,7 +240,8 @@ let loadEffect = (
|
|
|
289
240
|
}
|
|
290
241
|
) {
|
|
291
242
|
let storage = persistence->Persistence.getInitializedStorageOrThrow
|
|
292
|
-
let timerRef =
|
|
243
|
+
let timerRef =
|
|
244
|
+
indexerState->IndexerState.startStorageLoad(~storage=storage.name, ~operation=key)
|
|
293
245
|
let {outputSchema} = effect.storageMeta
|
|
294
246
|
|
|
295
247
|
let dbEntities = try {
|
|
@@ -319,8 +271,7 @@ let loadEffect = (
|
|
|
319
271
|
inMemTable->InMemoryStore.initEffectOutputFromDb(~cacheKey=dbEntity.id, ~output)
|
|
320
272
|
} catch {
|
|
321
273
|
| S.Raised(error) =>
|
|
322
|
-
inMemTable.
|
|
323
|
-
Prometheus.EffectCacheInvalidationsCount.increment(~effectName)
|
|
274
|
+
inMemTable->EffectState.recordInvalidation
|
|
324
275
|
Ecosystem.getItemLogger(item, ~ecosystem)->Logging.childTrace({
|
|
325
276
|
"msg": "Invalidated effect cache",
|
|
326
277
|
"input": dbEntity.id,
|
|
@@ -330,7 +281,8 @@ let loadEffect = (
|
|
|
330
281
|
}
|
|
331
282
|
})
|
|
332
283
|
|
|
333
|
-
|
|
284
|
+
indexerState->IndexerState.endStorageLoad(
|
|
285
|
+
timerRef,
|
|
334
286
|
~storage=storage.name,
|
|
335
287
|
~operation=key,
|
|
336
288
|
~whereSize=idsToLoad->Array.length,
|
|
@@ -386,7 +338,8 @@ let loadByFilter = (
|
|
|
386
338
|
|
|
387
339
|
let load = async (filters: array<EntityFilter.t>, ~onError as _) => {
|
|
388
340
|
let storage = persistence->Persistence.getInitializedStorageOrThrow
|
|
389
|
-
let timerRef =
|
|
341
|
+
let timerRef =
|
|
342
|
+
indexerState->IndexerState.startStorageLoad(~storage=storage.name, ~operation=key)
|
|
390
343
|
|
|
391
344
|
let size = ref(0)
|
|
392
345
|
|
|
@@ -434,7 +387,8 @@ let loadByFilter = (
|
|
|
434
387
|
})
|
|
435
388
|
->Promise.all
|
|
436
389
|
|
|
437
|
-
|
|
390
|
+
indexerState->IndexerState.endStorageLoad(
|
|
391
|
+
timerRef,
|
|
438
392
|
~storage=storage.name,
|
|
439
393
|
~operation=key,
|
|
440
394
|
~whereSize=queries->Array.reduce(0, (acc, query) => acc + query->EntityFilter.valuesCount),
|
package/src/LoadLayer.res.mjs
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
import * as Table from "./db/Table.res.mjs";
|
|
4
4
|
import * as Utils from "./Utils.res.mjs";
|
|
5
5
|
import * as Logging from "./Logging.res.mjs";
|
|
6
|
-
import * as Internal from "./Internal.res.mjs";
|
|
7
6
|
import * as Ecosystem from "./Ecosystem.res.mjs";
|
|
8
|
-
import * as
|
|
7
|
+
import * as EffectState from "./EffectState.res.mjs";
|
|
9
8
|
import * as LoadManager from "./LoadManager.res.mjs";
|
|
10
9
|
import * as Performance from "./bindings/Performance.res.mjs";
|
|
11
10
|
import * as Persistence from "./Persistence.res.mjs";
|
|
@@ -23,7 +22,7 @@ function loadById(loadManager, persistence, entityConfig, indexerState, shouldGr
|
|
|
23
22
|
let inMemTable = InMemoryStore.getInMemTable(indexerState, entityConfig);
|
|
24
23
|
let load = async (idsToLoad, param) => {
|
|
25
24
|
let storage = Persistence.getInitializedStorageOrThrow(persistence);
|
|
26
|
-
let timerRef =
|
|
25
|
+
let timerRef = IndexerState.startStorageLoad(indexerState, storage.name, key);
|
|
27
26
|
let dbEntities;
|
|
28
27
|
try {
|
|
29
28
|
dbEntities = await storage.loadOrThrow({
|
|
@@ -45,55 +44,17 @@ function loadById(loadManager, persistence, entityConfig, indexerState, shouldGr
|
|
|
45
44
|
entitiesMap[entity.id] = entity;
|
|
46
45
|
}
|
|
47
46
|
idsToLoad.forEach(entityId => InMemoryTable.Entity.initValue(inMemTable, IndexerState.committedCheckpointId(indexerState), entityId, entitiesMap[entityId]));
|
|
48
|
-
return
|
|
47
|
+
return IndexerState.endStorageLoad(indexerState, timerRef, storage.name, key, idsToLoad.length, dbEntities.length);
|
|
49
48
|
};
|
|
50
49
|
return LoadManager.call(loadManager, entityId, key, load, LoadManager.noopHasher, shouldGroup, hash => hash in inMemTable.latestEntityChangeById, InMemoryTable.Entity.getUnsafe(inMemTable));
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
function callEffect(effect, arg, inMemTable, timerRef, onError) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
let hadActiveCalls = inMemTable.activeCallsCount > 0;
|
|
57
|
-
inMemTable.activeCallsCount = inMemTable.activeCallsCount + 1 | 0;
|
|
58
|
-
Prometheus.SafeGauge.handleInt(Prometheus.EffectCalls.activeCallsCount, {
|
|
59
|
-
effect: effectName,
|
|
60
|
-
scope: scopeLabel
|
|
61
|
-
}, inMemTable.activeCallsCount);
|
|
62
|
-
if (hadActiveCalls) {
|
|
63
|
-
let elapsed = Performance.secondsBetween(inMemTable.prevCallStartTimerRef, timerRef);
|
|
64
|
-
if (elapsed > 0) {
|
|
65
|
-
Prometheus.SafeCounter.handleFloat(Prometheus.EffectCalls.timeCounter, {
|
|
66
|
-
effect: effectName,
|
|
67
|
-
scope: scopeLabel
|
|
68
|
-
}, elapsed);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
inMemTable.prevCallStartTimerRef = timerRef;
|
|
72
|
-
return effect.handler(arg).then(output => InMemoryStore.setEffectOutput(inMemTable, arg.checkpointId, arg.cacheKey, output, arg.context.cache)).catch(exn => onError(arg.cacheKey, exn)).finally(() => {
|
|
73
|
-
inMemTable.activeCallsCount = inMemTable.activeCallsCount - 1 | 0;
|
|
74
|
-
Prometheus.SafeGauge.handleInt(Prometheus.EffectCalls.activeCallsCount, {
|
|
75
|
-
effect: effectName,
|
|
76
|
-
scope: scopeLabel
|
|
77
|
-
}, inMemTable.activeCallsCount);
|
|
78
|
-
let newTimer = Performance.now();
|
|
79
|
-
Prometheus.SafeCounter.handleFloat(Prometheus.EffectCalls.timeCounter, {
|
|
80
|
-
effect: effectName,
|
|
81
|
-
scope: scopeLabel
|
|
82
|
-
}, Performance.secondsBetween(inMemTable.prevCallStartTimerRef, newTimer));
|
|
83
|
-
inMemTable.prevCallStartTimerRef = newTimer;
|
|
84
|
-
Prometheus.SafeCounter.increment(Prometheus.EffectCalls.totalCallsCount, {
|
|
85
|
-
effect: effectName,
|
|
86
|
-
scope: scopeLabel
|
|
87
|
-
});
|
|
88
|
-
Prometheus.SafeCounter.handleFloat(Prometheus.EffectCalls.sumTimeCounter, {
|
|
89
|
-
effect: effectName,
|
|
90
|
-
scope: scopeLabel
|
|
91
|
-
}, Performance.secondsSince(timerRef));
|
|
92
|
-
});
|
|
53
|
+
EffectState.startCall(inMemTable.stats, timerRef);
|
|
54
|
+
return effect.handler(arg).then(output => InMemoryStore.setEffectOutput(inMemTable, arg.checkpointId, arg.cacheKey, output, arg.context.cache)).catch(exn => onError(arg.cacheKey, exn)).finally(() => EffectState.endCall(inMemTable.stats, timerRef));
|
|
93
55
|
}
|
|
94
56
|
|
|
95
57
|
function executeWithRateLimit(effect, effectArgs, inMemTable, onError, isFromQueue) {
|
|
96
|
-
let effectName = effect.name;
|
|
97
58
|
let timerRef = Performance.now();
|
|
98
59
|
let promises = [];
|
|
99
60
|
let state = inMemTable.rateLimitState;
|
|
@@ -112,13 +73,11 @@ function executeWithRateLimit(effect, effectArgs, inMemTable, onError, isFromQue
|
|
|
112
73
|
promises.push(callEffect(effect, immediateArgs[idx], inMemTable, timerRef, onError));
|
|
113
74
|
}
|
|
114
75
|
if (immediateCount > 0 && isFromQueue) {
|
|
115
|
-
|
|
116
|
-
Prometheus.EffectQueueCount.set(state.queueCount, effectName, Internal.EffectCache.scopeToString(inMemTable.scope));
|
|
76
|
+
EffectState.queueDequeued(inMemTable.stats, immediateCount);
|
|
117
77
|
}
|
|
118
78
|
if (Utils.$$Array.notEmpty(queuedArgs)) {
|
|
119
79
|
if (!isFromQueue) {
|
|
120
|
-
|
|
121
|
-
Prometheus.EffectQueueCount.set(state.queueCount, effectName, Internal.EffectCache.scopeToString(inMemTable.scope));
|
|
80
|
+
EffectState.queueEnqueued(inMemTable.stats, queuedArgs.length);
|
|
122
81
|
}
|
|
123
82
|
let millisUntilReset = {
|
|
124
83
|
contents: 0
|
|
@@ -135,7 +94,7 @@ function executeWithRateLimit(effect, effectArgs, inMemTable, onError, isFromQue
|
|
|
135
94
|
}
|
|
136
95
|
promises.push(nextWindowPromise.then(() => {
|
|
137
96
|
if (millisUntilReset.contents > 0) {
|
|
138
|
-
|
|
97
|
+
EffectState.addQueueWaitSeconds(inMemTable.stats, millisUntilReset.contents / 1000);
|
|
139
98
|
}
|
|
140
99
|
return executeWithRateLimit(effect, queuedArgs, inMemTable, onError, true);
|
|
141
100
|
}));
|
|
@@ -163,7 +122,7 @@ function loadEffect(loadManager, persistence, effect, effectArgs, scope, indexer
|
|
|
163
122
|
tmp = typeof match !== "object" || match.TAG === "Initializing" ? false : tableName in match._0.cache;
|
|
164
123
|
if (tmp) {
|
|
165
124
|
let storage = Persistence.getInitializedStorageOrThrow(persistence);
|
|
166
|
-
let timerRef =
|
|
125
|
+
let timerRef = IndexerState.startStorageLoad(indexerState, storage.name, key);
|
|
167
126
|
let match$1 = effect.storageMeta;
|
|
168
127
|
let outputSchema = match$1.outputSchema;
|
|
169
128
|
let dbEntities;
|
|
@@ -190,8 +149,7 @@ function loadEffect(loadManager, persistence, effect, effectArgs, scope, indexer
|
|
|
190
149
|
} catch (raw_error) {
|
|
191
150
|
let error = Primitive_exceptions.internalToException(raw_error);
|
|
192
151
|
if (error.RE_EXN_ID === S$RescriptSchema.Raised) {
|
|
193
|
-
|
|
194
|
-
Prometheus.EffectCacheInvalidationsCount.increment(effectName);
|
|
152
|
+
EffectState.recordInvalidation(inMemTable);
|
|
195
153
|
return Logging.childTrace(Ecosystem.getItemLogger(item, ecosystem), {
|
|
196
154
|
msg: "Invalidated effect cache",
|
|
197
155
|
input: dbEntity.id,
|
|
@@ -202,7 +160,7 @@ function loadEffect(loadManager, persistence, effect, effectArgs, scope, indexer
|
|
|
202
160
|
throw error;
|
|
203
161
|
}
|
|
204
162
|
});
|
|
205
|
-
|
|
163
|
+
IndexerState.endStorageLoad(indexerState, timerRef, storage.name, key, idsToLoad.length, dbEntities.length);
|
|
206
164
|
}
|
|
207
165
|
let remainingCallsCount = idsToLoad.length - idsFromCache.size | 0;
|
|
208
166
|
if (remainingCallsCount <= 0) {
|
|
@@ -227,7 +185,7 @@ function loadByFilter(loadManager, persistence, entityConfig, indexerState, shou
|
|
|
227
185
|
let inMemTable = InMemoryStore.getInMemTable(indexerState, entityConfig);
|
|
228
186
|
let load = async (filters, param) => {
|
|
229
187
|
let storage = Persistence.getInitializedStorageOrThrow(persistence);
|
|
230
|
-
let timerRef =
|
|
188
|
+
let timerRef = IndexerState.startStorageLoad(indexerState, storage.name, key);
|
|
231
189
|
let size = {
|
|
232
190
|
contents: 0
|
|
233
191
|
};
|
|
@@ -250,7 +208,7 @@ function loadByFilter(loadManager, persistence, entityConfig, indexerState, shou
|
|
|
250
208
|
throw exn;
|
|
251
209
|
}
|
|
252
210
|
}));
|
|
253
|
-
return
|
|
211
|
+
return IndexerState.endStorageLoad(indexerState, timerRef, storage.name, key, Stdlib_Array.reduce(queries, 0, (acc, query) => acc + EntityFilter.valuesCount(query) | 0), size.contents);
|
|
254
212
|
};
|
|
255
213
|
return LoadManager.call(loadManager, filter, key, load, EntityFilter.toString, shouldGroup, InMemoryTable.Entity.hasIndex(inMemTable), InMemoryTable.Entity.getUnsafeOnIndex(inMemTable));
|
|
256
214
|
}
|