UNPKG

envio

Version:

A latency and sync speed optimized, developer friendly blockchain data indexer.

245 lines (231 loc) • 9 kB
// Generated by ReScript, PLEASE EDIT WITH CARE import * as Utils from "./Utils.res.mjs"; import * as Hrtime from "./bindings/Hrtime.res.mjs"; import * as Logging from "./Logging.res.mjs"; import * as ChainMap from "./ChainMap.res.mjs"; import * as Ecosystem from "./Ecosystem.res.mjs"; import * as Prometheus from "./Prometheus.res.mjs"; import * as Persistence from "./Persistence.res.mjs"; import * as UserContext from "./UserContext.res.mjs"; import * as ChainFetcher from "./ChainFetcher.res.mjs"; import * as ErrorHandling from "./ErrorHandling.res.mjs"; import * as InMemoryStore from "./InMemoryStore.res.mjs"; import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js"; function allChainsEventsProcessedToEndblock(chainFetchers) { return ChainMap.values(chainFetchers).every(ChainFetcher.hasProcessedToEndblock); } function computeChainsState(chainFetchers) { let chains = {}; let isRealtime = ChainMap.values(chainFetchers).every(ChainFetcher.isReady); ChainMap.keys(chainFetchers).forEach(chain => { chains[chain.toString()] = { id: chain, isRealtime: isRealtime }; }); return chains; } let ProcessingError = /* @__PURE__ */Primitive_exceptions.create("EventProcessing.ProcessingError"); async function runEventHandlerOrThrow(item, checkpointId, handler, inMemoryStore, loadManager, persistence, chains, config) { let timeBeforeHandler = Hrtime.makeTimer(); try { let contextParams = { item: item, checkpointId: checkpointId, inMemoryStore: inMemoryStore, loadManager: loadManager, persistence: persistence, isPreload: false, chains: chains, config: config, isResolved: false }; await handler({ event: item.event, context: UserContext.getHandlerContext(contextParams) }); contextParams.isResolved = true; } catch (raw_exn) { let exn = Primitive_exceptions.internalToException(raw_exn); throw { RE_EXN_ID: ProcessingError, message: "Unexpected error in the event handler. Please handle the error to keep the indexer running smoothly.", exn: exn, item: item, Error: new Error() }; } let handlerDuration = Hrtime.toSecondsFloat(Hrtime.timeSince(timeBeforeHandler)); return Prometheus.ProcessingHandler.increment(item.eventConfig.contractName, item.eventConfig.name, handlerDuration); } async function runHandlerOrThrow(item, checkpointId, inMemoryStore, loadManager, ctx, chains) { if (item.kind === 0) { let handler = item.eventConfig.handler; if (handler !== undefined) { return await runEventHandlerOrThrow(item, checkpointId, handler, inMemoryStore, loadManager, ctx.persistence, chains, ctx.config); } else { return; } } try { let contextParams = { item: item, checkpointId: checkpointId, inMemoryStore: inMemoryStore, loadManager: loadManager, persistence: ctx.persistence, isPreload: false, chains: chains, config: ctx.config, isResolved: false }; await item.onBlockConfig.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, ctx.config.ecosystem, UserContext.getHandlerContext(contextParams))); contextParams.isResolved = true; return; } catch (raw_exn) { let exn = Primitive_exceptions.internalToException(raw_exn); throw { RE_EXN_ID: ProcessingError, message: "Unexpected error in the block handler. Please handle the error to keep the indexer running smoothly.", exn: exn, item: item, Error: new Error() }; } } async function preloadBatchOrThrow(batch, loadManager, persistence, config, inMemoryStore, chains) { let promises = []; let itemIdx = 0; for (let checkpointIdx = 0, checkpointIdx_finish = batch.checkpointIds.length; checkpointIdx < checkpointIdx_finish; ++checkpointIdx) { let checkpointId = batch.checkpointIds[checkpointIdx]; let checkpointEventsProcessed = batch.checkpointEventsProcessed[checkpointIdx]; for (let idx = 0; idx < checkpointEventsProcessed; ++idx) { let item = batch.items[itemIdx + idx | 0]; if (item.kind === 0) { let match = item.eventConfig; let handler = match.handler; if (handler !== undefined) { let contractName = match.contractName; let eventName = match.name; try { let timerRef = Prometheus.PreloadHandler.startOperation(contractName, eventName); promises.push(Utils.$$Promise.silentCatch(handler({ event: item.event, context: UserContext.getHandlerContext({ item: item, checkpointId: checkpointId, inMemoryStore: inMemoryStore, loadManager: loadManager, persistence: persistence, isPreload: true, chains: chains, config: config, isResolved: false }) }).then(() => Prometheus.PreloadHandler.endOperation(timerRef, contractName, eventName)))); } catch (exn) { } } } else { try { promises.push(Utils.$$Promise.silentCatch(item.onBlockConfig.handler(Ecosystem.makeOnBlockArgs(item.blockNumber, config.ecosystem, UserContext.getHandlerContext({ item: item, checkpointId: checkpointId, inMemoryStore: inMemoryStore, loadManager: loadManager, persistence: persistence, isPreload: true, chains: chains, config: config, isResolved: false }))))); } catch (exn$1) { } } } itemIdx = itemIdx + checkpointEventsProcessed | 0; } await Promise.all(promises); } async function runBatchHandlersOrThrow(batch, inMemoryStore, loadManager, ctx, chains) { let itemIdx = 0; for (let checkpointIdx = 0, checkpointIdx_finish = batch.checkpointIds.length; checkpointIdx < checkpointIdx_finish; ++checkpointIdx) { let checkpointId = batch.checkpointIds[checkpointIdx]; let checkpointEventsProcessed = batch.checkpointEventsProcessed[checkpointIdx]; for (let idx = 0; idx < checkpointEventsProcessed; ++idx) { let item = batch.items[itemIdx + idx | 0]; await runHandlerOrThrow(item, checkpointId, inMemoryStore, loadManager, ctx, chains); } itemIdx = itemIdx + checkpointEventsProcessed | 0; } } function registerProcessEventBatchMetrics(logger, loadDuration, handlerDuration) { Logging.childTrace(logger, { msg: "Finished processing batch", loader_time_elapsed: loadDuration, handlers_time_elapsed: handlerDuration }); Prometheus.ProcessingBatch.registerMetrics(loadDuration, handlerDuration); } async function processEventBatch(batch, inMemoryStore, loadManager, ctx, chainFetchers) { let totalBatchSize = batch.totalBatchSize; let chains = computeChainsState(chainFetchers); let logger = Logging.getLogger(); Logging.childTrace(logger, { msg: "Started processing batch", totalBatchSize: totalBatchSize, chains: Utils.Dict.mapValues(batch.progressedChainsById, chainAfterBatch => ({ batchSize: chainAfterBatch.batchSize, progress: chainAfterBatch.progressBlockNumber })) }); try { await InMemoryStore.awaitCapacity(inMemoryStore); let timeRef = Hrtime.makeTimer(); if (Utils.$$Array.notEmpty(batch.items)) { await preloadBatchOrThrow(batch, loadManager, ctx.persistence, ctx.config, inMemoryStore, chains); } let elapsedTimeAfterLoaders = Hrtime.toSecondsFloat(Hrtime.timeSince(timeRef)); if (Utils.$$Array.notEmpty(batch.items)) { await runBatchHandlersOrThrow(batch, inMemoryStore, loadManager, ctx, chains); } let elapsedTimeAfterProcessing = Hrtime.toSecondsFloat(Hrtime.timeSince(timeRef)); InMemoryStore.commitBatch(inMemoryStore, batch); let handlerDuration = elapsedTimeAfterProcessing - elapsedTimeAfterLoaders; registerProcessEventBatchMetrics(logger, elapsedTimeAfterLoaders, handlerDuration); return { TAG: "Ok", _0: undefined }; } catch (raw_exn) { let exn = Primitive_exceptions.internalToException(raw_exn); if (exn.RE_EXN_ID === Persistence.StorageError) { return { TAG: "Error", _0: ErrorHandling.make(exn.reason, logger, exn.message) }; } else if (exn.RE_EXN_ID === ProcessingError) { return { TAG: "Error", _0: ErrorHandling.make(exn.exn, Logging.getItemLogger(exn.item), exn.message) }; } else { return { TAG: "Error", _0: ErrorHandling.make(exn, logger, "Failed processing batch") }; } } } export { allChainsEventsProcessedToEndblock, computeChainsState, ProcessingError, runEventHandlerOrThrow, runHandlerOrThrow, preloadBatchOrThrow, runBatchHandlersOrThrow, registerProcessEventBatchMetrics, processEventBatch, } /* Utils Not a pure module */