envio
Version:
A latency and sync speed optimized, developer friendly blockchain data indexer.
245 lines (231 loc) • 9 kB
JavaScript
// 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 */