@secondlayer/subgraphs 3.10.0 → 3.12.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/README.md +5 -0
- package/dist/src/index.d.ts +29 -1
- package/dist/src/index.js +78 -3
- package/dist/src/index.js.map +6 -6
- package/dist/src/runtime/block-processor.d.ts +3 -0
- package/dist/src/runtime/block-processor.js +43 -3
- package/dist/src/runtime/block-processor.js.map +3 -3
- package/dist/src/runtime/catchup.d.ts +3 -0
- package/dist/src/runtime/catchup.js +43 -3
- package/dist/src/runtime/catchup.js.map +3 -3
- package/dist/src/runtime/processor.js +102 -4
- package/dist/src/runtime/processor.js.map +5 -5
- package/dist/src/runtime/reindex.d.ts +7 -0
- package/dist/src/runtime/reindex.js +74 -3
- package/dist/src/runtime/reindex.js.map +4 -4
- package/dist/src/runtime/reorg.d.ts +3 -0
- package/dist/src/runtime/reorg.js +43 -3
- package/dist/src/runtime/reorg.js.map +3 -3
- package/dist/src/runtime/replay.js +43 -3
- package/dist/src/runtime/replay.js.map +3 -3
- package/dist/src/runtime/runner.d.ts +3 -0
- package/dist/src/schema/index.d.ts +3 -0
- package/dist/src/schema/index.js +2 -1
- package/dist/src/schema/index.js.map +4 -4
- package/dist/src/service.js +102 -4
- package/dist/src/service.js.map +5 -5
- package/dist/src/types.d.ts +3 -0
- package/dist/src/validate.d.ts +3 -0
- package/dist/src/validate.js +2 -1
- package/dist/src/validate.js.map +3 -3
- package/package.json +2 -2
|
@@ -1119,6 +1119,28 @@ function reconstructEvent(e) {
|
|
|
1119
1119
|
}
|
|
1120
1120
|
|
|
1121
1121
|
// src/runtime/block-source.ts
|
|
1122
|
+
function canSparseScan(subgraph) {
|
|
1123
|
+
if (Array.isArray(subgraph.sources))
|
|
1124
|
+
return false;
|
|
1125
|
+
const filters = sourceFilters(subgraph);
|
|
1126
|
+
if (filters.length === 0)
|
|
1127
|
+
return false;
|
|
1128
|
+
return filters.every((f) => Boolean(EVENT_FILTER_TO_INDEX_TYPE[f.type]));
|
|
1129
|
+
}
|
|
1130
|
+
function sparseProbeTargets(subgraph) {
|
|
1131
|
+
const targets = new Map;
|
|
1132
|
+
for (const f of sourceFilters(subgraph)) {
|
|
1133
|
+
const eventType = EVENT_FILTER_TO_INDEX_TYPE[f.type];
|
|
1134
|
+
if (!eventType)
|
|
1135
|
+
continue;
|
|
1136
|
+
const scoped = f;
|
|
1137
|
+
const contractId = scoped.contractId ?? scoped.assetIdentifier?.split("::")[0];
|
|
1138
|
+
const key = `${eventType}|${contractId ?? ""}`;
|
|
1139
|
+
targets.set(key, { eventType, ...contractId ? { contractId } : {} });
|
|
1140
|
+
}
|
|
1141
|
+
return [...targets.values()];
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1122
1144
|
class PostgresBlockSource {
|
|
1123
1145
|
async getTip() {
|
|
1124
1146
|
const progress = await getSourceDb().selectFrom("index_progress").selectAll().where("network", "=", process.env.NETWORK ?? "mainnet").executeTakeFirst();
|
|
@@ -1181,9 +1203,18 @@ function isStreamsIndexEligible(subgraph) {
|
|
|
1181
1203
|
class PublicApiBlockSource {
|
|
1182
1204
|
http;
|
|
1183
1205
|
eventTypes;
|
|
1184
|
-
|
|
1206
|
+
probeTargets;
|
|
1207
|
+
constructor(http, eventTypes, probeTargets) {
|
|
1185
1208
|
this.http = http;
|
|
1186
1209
|
this.eventTypes = eventTypes;
|
|
1210
|
+
this.probeTargets = probeTargets;
|
|
1211
|
+
}
|
|
1212
|
+
async nextDataHeight(afterHeight, untilHeight) {
|
|
1213
|
+
if (!this.probeTargets?.length)
|
|
1214
|
+
return afterHeight + 1;
|
|
1215
|
+
const hits = await Promise.all(this.probeTargets.map((t) => this.http.firstEventHeight(t.eventType, afterHeight + 1, untilHeight, t.contractId)));
|
|
1216
|
+
const found = hits.filter((h) => h !== null);
|
|
1217
|
+
return found.length ? Math.min(...found) : null;
|
|
1187
1218
|
}
|
|
1188
1219
|
getTip() {
|
|
1189
1220
|
return this.http.getIndexTip();
|
|
@@ -1247,6 +1278,15 @@ class FallbackBlockSource {
|
|
|
1247
1278
|
return this.fallback.loadBlockRange(fromHeight, toHeight);
|
|
1248
1279
|
}
|
|
1249
1280
|
}
|
|
1281
|
+
async nextDataHeight(afterHeight, untilHeight) {
|
|
1282
|
+
if (!this.primary.nextDataHeight)
|
|
1283
|
+
return afterHeight + 1;
|
|
1284
|
+
try {
|
|
1285
|
+
return await this.primary.nextDataHeight(afterHeight, untilHeight);
|
|
1286
|
+
} catch {
|
|
1287
|
+
return afterHeight + 1;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1250
1290
|
}
|
|
1251
1291
|
var postgresBlockSource = new PostgresBlockSource;
|
|
1252
1292
|
function buildHttpClient() {
|
|
@@ -1259,7 +1299,7 @@ function buildHttpClient() {
|
|
|
1259
1299
|
}
|
|
1260
1300
|
function resolveBlockSource(subgraph) {
|
|
1261
1301
|
if (process.env.SUBGRAPH_SOURCE === "streams-index" && subgraph && isStreamsIndexEligible(subgraph)) {
|
|
1262
|
-
return new FallbackBlockSource(new PublicApiBlockSource(buildHttpClient(), referencedIndexEventTypes(subgraph)), postgresBlockSource);
|
|
1302
|
+
return new FallbackBlockSource(new PublicApiBlockSource(buildHttpClient(), referencedIndexEventTypes(subgraph), canSparseScan(subgraph) ? sparseProbeTargets(subgraph) : undefined), postgresBlockSource);
|
|
1263
1303
|
}
|
|
1264
1304
|
if (process.env.SUBGRAPH_SOURCE === "streams-index" && subgraph) {
|
|
1265
1305
|
logger3.debug("Subgraph not streams-index eligible, using DB tap", {
|
|
@@ -1742,6 +1782,7 @@ import {
|
|
|
1742
1782
|
recordGapBatch,
|
|
1743
1783
|
resolveGaps
|
|
1744
1784
|
} from "@secondlayer/shared/db/queries/subgraph-gaps";
|
|
1785
|
+
import { updateOperationProcessedEvents } from "@secondlayer/shared/db/queries/subgraph-operations";
|
|
1745
1786
|
import {
|
|
1746
1787
|
recordSubgraphProcessed as recordSubgraphProcessed2,
|
|
1747
1788
|
updateSubgraphStatus as updateSubgraphStatus2
|
|
@@ -1929,6 +1970,7 @@ async function processBlockRange(def, opts) {
|
|
|
1929
1970
|
let batchSize = batchConfig.defaultBatchSize;
|
|
1930
1971
|
let currentHeight = fromBlock;
|
|
1931
1972
|
let aborted = false;
|
|
1973
|
+
const sparse = Boolean(source.nextDataHeight && canSparseScan(def));
|
|
1932
1974
|
const flushHealth = async () => {
|
|
1933
1975
|
if (pendingEventsProcessed === 0 && pendingErrors === 0)
|
|
1934
1976
|
return;
|
|
@@ -1959,6 +2001,7 @@ async function processBlockRange(def, opts) {
|
|
|
1959
2001
|
nextBatchPromise = source.loadBlockRange(nextStart, nextBatchEnd);
|
|
1960
2002
|
}
|
|
1961
2003
|
const batchFailedBlocks = [];
|
|
2004
|
+
let batchMatched = 0;
|
|
1962
2005
|
for (let height = currentHeight;height <= batchEnd; height++) {
|
|
1963
2006
|
const blockData = batch.get(height);
|
|
1964
2007
|
if (!blockData) {
|
|
@@ -1988,6 +2031,7 @@ async function processBlockRange(def, opts) {
|
|
|
1988
2031
|
continue;
|
|
1989
2032
|
}
|
|
1990
2033
|
blocksProcessed++;
|
|
2034
|
+
batchMatched += result.matched;
|
|
1991
2035
|
totalEventsProcessed += result.processed;
|
|
1992
2036
|
totalErrors += result.errors;
|
|
1993
2037
|
pendingEventsProcessed += result.processed;
|
|
@@ -2005,6 +2049,9 @@ async function processBlockRange(def, opts) {
|
|
|
2005
2049
|
const shouldFlushProgress = blocksProcessed % 100 === 0 || now - lastProgressFlushAt >= PROGRESS_FLUSH_INTERVAL_MS;
|
|
2006
2050
|
if (shouldFlushProgress) {
|
|
2007
2051
|
await updateSubgraphStatus2(targetDb, subgraphName, status, height);
|
|
2052
|
+
if (opts.operationId) {
|
|
2053
|
+
await updateOperationProcessedEvents(targetDb, opts.operationId, totalEventsProcessed).catch(() => {});
|
|
2054
|
+
}
|
|
2008
2055
|
lastProgressFlushAt = now;
|
|
2009
2056
|
}
|
|
2010
2057
|
if (blocksProcessed % LOG_INTERVAL === 0) {
|
|
@@ -2033,6 +2080,27 @@ async function processBlockRange(def, opts) {
|
|
|
2033
2080
|
});
|
|
2034
2081
|
});
|
|
2035
2082
|
}
|
|
2083
|
+
if (sparse && batchMatched === 0 && batchEnd < toBlock && source.nextDataHeight) {
|
|
2084
|
+
const next = await source.nextDataHeight(batchEnd, toBlock);
|
|
2085
|
+
const jumpTo = next === null ? toBlock + 1 : Math.max(next, batchEnd + 1);
|
|
2086
|
+
if (jumpTo > batchEnd + 1) {
|
|
2087
|
+
const skipped = Math.min(jumpTo, toBlock + 1) - (batchEnd + 1);
|
|
2088
|
+
blocksProcessed += skipped;
|
|
2089
|
+
await updateSubgraphStatus2(targetDb, subgraphName, status, jumpTo - 1);
|
|
2090
|
+
logger6.info("Sparse skip", {
|
|
2091
|
+
subgraph: subgraphName,
|
|
2092
|
+
from: batchEnd + 1,
|
|
2093
|
+
to: jumpTo - 1,
|
|
2094
|
+
skipped
|
|
2095
|
+
});
|
|
2096
|
+
currentHeight = jumpTo;
|
|
2097
|
+
if (currentHeight <= toBlock) {
|
|
2098
|
+
nextBatchEnd = Math.min(currentHeight + batchSize - 1, toBlock);
|
|
2099
|
+
nextBatchPromise = source.loadBlockRange(currentHeight, nextBatchEnd);
|
|
2100
|
+
}
|
|
2101
|
+
continue;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2036
2104
|
const avg = avgEventsPerBlock(batch);
|
|
2037
2105
|
if (avg > 50)
|
|
2038
2106
|
batchSize = Math.max(Math.round(batchSize * 0.5), batchConfig.minBatchSize);
|
|
@@ -2101,6 +2169,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
2101
2169
|
isCatchup: false,
|
|
2102
2170
|
apiKeyId: null,
|
|
2103
2171
|
subgraphId: subgraphRow?.id,
|
|
2172
|
+
operationId: opts?.operationId,
|
|
2104
2173
|
signal: opts?.signal
|
|
2105
2174
|
});
|
|
2106
2175
|
if (result.aborted) {
|
|
@@ -2176,6 +2245,7 @@ async function resumeReindex(def, opts) {
|
|
|
2176
2245
|
isCatchup: false,
|
|
2177
2246
|
apiKeyId: null,
|
|
2178
2247
|
subgraphId: row.id,
|
|
2248
|
+
operationId: opts.operationId,
|
|
2179
2249
|
signal: opts.signal
|
|
2180
2250
|
});
|
|
2181
2251
|
if (result.aborted) {
|
|
@@ -2224,6 +2294,7 @@ async function backfillSubgraph(def, opts) {
|
|
|
2224
2294
|
isCatchup: false,
|
|
2225
2295
|
apiKeyId: null,
|
|
2226
2296
|
subgraphId: subgraphRow?.id,
|
|
2297
|
+
operationId: opts.operationId,
|
|
2227
2298
|
signal: opts.signal
|
|
2228
2299
|
});
|
|
2229
2300
|
if (result.aborted) {
|
|
@@ -2766,6 +2837,7 @@ async function runSubgraphOperation(operation, signal) {
|
|
|
2766
2837
|
fromBlock: Number(operation.from_block),
|
|
2767
2838
|
toBlock: Number(operation.to_block),
|
|
2768
2839
|
schemaName,
|
|
2840
|
+
operationId: operation.id,
|
|
2769
2841
|
signal
|
|
2770
2842
|
});
|
|
2771
2843
|
return result2.processed;
|
|
@@ -2775,13 +2847,18 @@ async function runSubgraphOperation(operation, signal) {
|
|
|
2775
2847
|
}
|
|
2776
2848
|
const hasResumeMetadata = subgraph.status === "reindexing" && subgraph.reindex_from_block != null && subgraph.reindex_to_block != null;
|
|
2777
2849
|
if (hasResumeMetadata) {
|
|
2778
|
-
const result2 = await resumeReindex(def, {
|
|
2850
|
+
const result2 = await resumeReindex(def, {
|
|
2851
|
+
schemaName,
|
|
2852
|
+
operationId: operation.id,
|
|
2853
|
+
signal
|
|
2854
|
+
});
|
|
2779
2855
|
return result2.processed;
|
|
2780
2856
|
}
|
|
2781
2857
|
const result = await reindexSubgraph(def, {
|
|
2782
2858
|
fromBlock: operation.from_block == null ? undefined : Number(operation.from_block),
|
|
2783
2859
|
toBlock: operation.to_block == null ? undefined : Number(operation.to_block),
|
|
2784
2860
|
schemaName,
|
|
2861
|
+
operationId: operation.id,
|
|
2785
2862
|
signal
|
|
2786
2863
|
});
|
|
2787
2864
|
return result.processed;
|
|
@@ -2795,6 +2872,27 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
2795
2872
|
let running = true;
|
|
2796
2873
|
let draining = false;
|
|
2797
2874
|
logger10.info("Starting subgraph operation runner", { concurrency, lockedBy });
|
|
2875
|
+
try {
|
|
2876
|
+
const stranded = await db.selectFrom("subgraphs").select(["id", "name", "account_id"]).where("status", "=", "reindexing").where("reindex_from_block", "is not", null).where("reindex_to_block", "is not", null).where(({ not, exists, selectFrom }) => not(exists(selectFrom("subgraph_operations").select("id").whereRef("subgraph_id", "=", "subgraphs.id").where("status", "in", ["queued", "running"])))).execute();
|
|
2877
|
+
for (const row of stranded) {
|
|
2878
|
+
try {
|
|
2879
|
+
await createSubgraphOperation(db, {
|
|
2880
|
+
subgraphId: row.id,
|
|
2881
|
+
subgraphName: row.name,
|
|
2882
|
+
accountId: row.account_id,
|
|
2883
|
+
kind: "reindex"
|
|
2884
|
+
});
|
|
2885
|
+
logger10.info("Re-enqueued stranded reindex", { subgraph: row.name });
|
|
2886
|
+
} catch (err) {
|
|
2887
|
+
if (!isActiveSubgraphOperationConflict(err))
|
|
2888
|
+
throw err;
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
} catch (err) {
|
|
2892
|
+
logger10.warn("Stranded-reindex sweep failed", {
|
|
2893
|
+
error: getErrorMessage5(err)
|
|
2894
|
+
});
|
|
2895
|
+
}
|
|
2798
2896
|
const startOperation = (operation) => {
|
|
2799
2897
|
const controller = new AbortController;
|
|
2800
2898
|
active.set(operation.id, controller);
|
|
@@ -2970,5 +3068,5 @@ export {
|
|
|
2970
3068
|
startSubgraphOperationRunner
|
|
2971
3069
|
};
|
|
2972
3070
|
|
|
2973
|
-
//# debugId=
|
|
3071
|
+
//# debugId=CA67CC38C44D43DF64756E2164756E21
|
|
2974
3072
|
//# sourceMappingURL=processor.js.map
|