envio 3.3.0 → 3.3.1

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.
Files changed (54) hide show
  1. package/package.json +6 -7
  2. package/src/ChainFetching.res +4 -32
  3. package/src/ChainFetching.res.mjs +2 -12
  4. package/src/ChainState.res +73 -53
  5. package/src/ChainState.res.mjs +61 -30
  6. package/src/ChainState.resi +13 -17
  7. package/src/Config.res +5 -0
  8. package/src/Config.res.mjs +1 -0
  9. package/src/CrossChainState.res +2 -8
  10. package/src/CrossChainState.res.mjs +6 -8
  11. package/src/CrossChainState.resi +1 -0
  12. package/src/EffectState.res +183 -44
  13. package/src/EffectState.res.mjs +134 -26
  14. package/src/EffectState.resi +26 -3
  15. package/src/EventProcessing.res +14 -9
  16. package/src/EventProcessing.res.mjs +7 -7
  17. package/src/FetchState.res +18 -29
  18. package/src/FetchState.res.mjs +20 -37
  19. package/src/IndexerState.res +280 -31
  20. package/src/IndexerState.res.mjs +234 -25
  21. package/src/IndexerState.resi +22 -0
  22. package/src/LoadLayer.res +19 -65
  23. package/src/LoadLayer.res.mjs +13 -55
  24. package/src/Main.res +42 -23
  25. package/src/Main.res.mjs +32 -35
  26. package/src/Metrics.res +943 -66
  27. package/src/Metrics.res.mjs +367 -50
  28. package/src/Persistence.res +3 -0
  29. package/src/PgStorage.res +3 -8
  30. package/src/PgStorage.res.mjs +3 -4
  31. package/src/PruneStaleHistory.res +1 -1
  32. package/src/PruneStaleHistory.res.mjs +1 -2
  33. package/src/Rollback.res +4 -5
  34. package/src/Rollback.res.mjs +2 -3
  35. package/src/SimulateItems.res.mjs +3 -21
  36. package/src/TestIndexer.res.mjs +4 -23
  37. package/src/TestIndexerProxyStorage.res +1 -0
  38. package/src/TestIndexerProxyStorage.res.mjs +1 -1
  39. package/src/Writing.res +3 -5
  40. package/src/Writing.res.mjs +3 -6
  41. package/src/bindings/ClickHouse.res +101 -17
  42. package/src/bindings/ClickHouse.res.mjs +58 -19
  43. package/src/bindings/NodeJs.res +64 -0
  44. package/src/bindings/NodeJs.res.mjs +6 -0
  45. package/src/sources/HyperSyncClient.res +5 -11
  46. package/src/sources/SourceManager.res +72 -27
  47. package/src/sources/SourceManager.res.mjs +81 -11
  48. package/src/sources/SourceManager.resi +14 -0
  49. package/src/tui/Tui.res +1 -1
  50. package/src/tui/Tui.res.mjs +2 -2
  51. package/src/Prometheus.res +0 -789
  52. package/src/Prometheus.res.mjs +0 -847
  53. package/src/bindings/PromClient.res +0 -72
  54. package/src/bindings/PromClient.res.mjs +0 -38
@@ -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 allChainsReady = {
118
- contents: initialState.chains.length !== 0
119
- };
120
- Utils.Dict.forEach(chainStates, cs => {
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
- if (allChainsReady.contents) {
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,
@@ -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 = Prometheus.StorageLoad.startOperation(~storage=storage.name, ~operation=key)
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
- timerRef->Prometheus.StorageLoad.endOperation(
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
- let effectName = effect.name
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.activeCallsCount = inMemTable.activeCallsCount - 1
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
- // Update queue count metric
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
- // Update queue count metric
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
- Prometheus.EffectQueueCount.timeCounter->Prometheus.SafeCounter.handleFloat(
236
- ~labels=effectName,
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 = Prometheus.StorageLoad.startOperation(~storage=storage.name, ~operation=key)
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.invalidationsCount = inMemTable.invalidationsCount + 1
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
- timerRef->Prometheus.StorageLoad.endOperation(
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 = Prometheus.StorageLoad.startOperation(~storage=storage.name, ~operation=key)
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
- timerRef->Prometheus.StorageLoad.endOperation(
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),
@@ -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 Prometheus from "./Prometheus.res.mjs";
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 = Prometheus.StorageLoad.startOperation(storage.name, key);
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 Prometheus.StorageLoad.endOperation(timerRef, storage.name, key, idsToLoad.length, dbEntities.length);
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
- let effectName = effect.name;
55
- let scopeLabel = Internal.EffectCache.scopeToString(inMemTable.scope);
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
- state.queueCount = state.queueCount - immediateCount | 0;
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
- state.queueCount = state.queueCount + queuedArgs.length | 0;
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
- Prometheus.SafeCounter.handleFloat(Prometheus.EffectQueueCount.timeCounter, effectName, millisUntilReset.contents / 1000);
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 = Prometheus.StorageLoad.startOperation(storage.name, key);
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
- inMemTable.invalidationsCount = inMemTable.invalidationsCount + 1 | 0;
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
- Prometheus.StorageLoad.endOperation(timerRef, storage.name, key, idsToLoad.length, dbEntities.length);
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 = Prometheus.StorageLoad.startOperation(storage.name, key);
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 Prometheus.StorageLoad.endOperation(timerRef, storage.name, key, Stdlib_Array.reduce(queries, 0, (acc, query) => acc + EntityFilter.valuesCount(query) | 0), size.contents);
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
  }