@secondlayer/subgraphs 1.0.0-alpha.0 → 1.0.0-beta.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.
- package/dist/src/index.js +261 -49
- package/dist/src/index.js.map +8 -5
- package/dist/src/runtime/block-processor.js +222 -10
- package/dist/src/runtime/block-processor.js.map +9 -6
- package/dist/src/runtime/catchup.js +229 -17
- package/dist/src/runtime/catchup.js.map +8 -5
- package/dist/src/runtime/context.d.ts +22 -2
- package/dist/src/runtime/context.js +24 -3
- package/dist/src/runtime/context.js.map +3 -3
- package/dist/src/runtime/processor.js +524 -37
- package/dist/src/runtime/processor.js.map +11 -6
- package/dist/src/runtime/reindex.js +247 -35
- package/dist/src/runtime/reindex.js.map +8 -5
- package/dist/src/runtime/reorg.js +227 -15
- package/dist/src/runtime/reorg.js.map +8 -5
- package/dist/src/runtime/runner.d.ts +21 -1
- package/dist/src/service.js +526 -39
- package/dist/src/service.js.map +11 -6
- package/package.json +2 -2
|
@@ -168,7 +168,7 @@ class SubgraphContext {
|
|
|
168
168
|
}
|
|
169
169
|
async flush() {
|
|
170
170
|
if (this.ops.length === 0)
|
|
171
|
-
return 0;
|
|
171
|
+
return { count: 0, writes: [] };
|
|
172
172
|
const opsToFlush = [...this.ops];
|
|
173
173
|
this.ops.length = 0;
|
|
174
174
|
const statements = this.buildStatements(opsToFlush);
|
|
@@ -183,7 +183,21 @@ class SubgraphContext {
|
|
|
183
183
|
}
|
|
184
184
|
});
|
|
185
185
|
}
|
|
186
|
-
|
|
186
|
+
const writes = opsToFlush.map((op, rowIndex) => {
|
|
187
|
+
const blockHeight = op.data._block_height ?? this.block.height;
|
|
188
|
+
const txId = op.data._tx_id ?? this._tx.txId;
|
|
189
|
+
const baseRow = op.kind === "update" ? { ...op.data, ...op.set ?? {} } : { ...op.data };
|
|
190
|
+
delete baseRow._upsert_keys;
|
|
191
|
+
delete baseRow._upsert_fallback_keys;
|
|
192
|
+
delete baseRow._upsert_fallback_set;
|
|
193
|
+
return {
|
|
194
|
+
op: op.kind,
|
|
195
|
+
table: op.table,
|
|
196
|
+
row: jsonSafe(baseRow),
|
|
197
|
+
pk: { blockHeight, txId, rowIndex }
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
return { count: opsToFlush.length, writes };
|
|
187
201
|
}
|
|
188
202
|
prepareInsert(op) {
|
|
189
203
|
const upsertKeys = op.data._upsert_keys;
|
|
@@ -276,6 +290,13 @@ class SubgraphContext {
|
|
|
276
290
|
}
|
|
277
291
|
}
|
|
278
292
|
}
|
|
293
|
+
function jsonSafe(row) {
|
|
294
|
+
const out = {};
|
|
295
|
+
for (const [k, v] of Object.entries(row)) {
|
|
296
|
+
out[k] = typeof v === "bigint" ? v.toString() : v;
|
|
297
|
+
}
|
|
298
|
+
return out;
|
|
299
|
+
}
|
|
279
300
|
function escapeLiteral(value) {
|
|
280
301
|
if (value === null || value === undefined)
|
|
281
302
|
return "NULL";
|
|
@@ -857,12 +878,200 @@ import {
|
|
|
857
878
|
recordSubgraphProcessed,
|
|
858
879
|
updateSubgraphStatus
|
|
859
880
|
} from "@secondlayer/shared/db/queries/subgraphs";
|
|
860
|
-
import { logger as
|
|
861
|
-
import { sql as
|
|
881
|
+
import { logger as logger4 } from "@secondlayer/shared/logger";
|
|
882
|
+
import { sql as sql3 } from "kysely";
|
|
862
883
|
|
|
863
884
|
// src/schema/utils.ts
|
|
864
885
|
import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
|
|
865
886
|
|
|
887
|
+
// src/runtime/outbox-emit.ts
|
|
888
|
+
import { createHash } from "node:crypto";
|
|
889
|
+
import { logger as logger3 } from "@secondlayer/shared/logger";
|
|
890
|
+
var loggedKillSwitch = false;
|
|
891
|
+
function isEmitOutboxEnabled() {
|
|
892
|
+
return process.env.SECONDLAYER_EMIT_OUTBOX !== "false";
|
|
893
|
+
}
|
|
894
|
+
function dedupKey(subgraphName, tableName, blockHeight, txId, rowIndex, row) {
|
|
895
|
+
const canonical = `${subgraphName}:${tableName}:${blockHeight}:${txId}:${rowIndex}:${stableStringify(row)}`;
|
|
896
|
+
return createHash("sha256").update(canonical).digest("hex").slice(0, 32);
|
|
897
|
+
}
|
|
898
|
+
function stableStringify(obj) {
|
|
899
|
+
const keys = Object.keys(obj).sort();
|
|
900
|
+
return JSON.stringify(keys.reduce((acc, k) => {
|
|
901
|
+
acc[k] = obj[k];
|
|
902
|
+
return acc;
|
|
903
|
+
}, {}));
|
|
904
|
+
}
|
|
905
|
+
async function emitSubscriptionOutbox(tx, subgraphName, manifest, matcher, blockHeight) {
|
|
906
|
+
if (!isEmitOutboxEnabled()) {
|
|
907
|
+
if (!loggedKillSwitch) {
|
|
908
|
+
logger3.warn("SECONDLAYER_EMIT_OUTBOX=false — outbox emission bypassed");
|
|
909
|
+
loggedKillSwitch = true;
|
|
910
|
+
}
|
|
911
|
+
return 0;
|
|
912
|
+
}
|
|
913
|
+
loggedKillSwitch = false;
|
|
914
|
+
if (manifest.count === 0 || matcher.size() === 0)
|
|
915
|
+
return 0;
|
|
916
|
+
const rows = [];
|
|
917
|
+
for (const write of manifest.writes) {
|
|
918
|
+
if (write.op !== "insert")
|
|
919
|
+
continue;
|
|
920
|
+
const subs = matcher.match(subgraphName, write.table, write.row);
|
|
921
|
+
if (subs.length === 0)
|
|
922
|
+
continue;
|
|
923
|
+
const eventType = `${subgraphName}.${write.table}.created`;
|
|
924
|
+
for (const s of subs) {
|
|
925
|
+
rows.push({
|
|
926
|
+
subscription_id: s.id,
|
|
927
|
+
subgraph_name: subgraphName,
|
|
928
|
+
table_name: write.table,
|
|
929
|
+
block_height: blockHeight,
|
|
930
|
+
tx_id: write.pk.txId || null,
|
|
931
|
+
row_pk: write.pk,
|
|
932
|
+
event_type: eventType,
|
|
933
|
+
payload: write.row,
|
|
934
|
+
dedup_key: dedupKey(subgraphName, write.table, write.pk.blockHeight, write.pk.txId, write.pk.rowIndex, write.row)
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
if (rows.length === 0)
|
|
939
|
+
return 0;
|
|
940
|
+
await tx.insertInto("subscription_outbox").values(rows).onConflict((oc) => oc.columns(["subscription_id", "dedup_key"]).doNothing()).execute();
|
|
941
|
+
return rows.length;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// src/runtime/subscription-state.ts
|
|
945
|
+
import { listSubscriptions } from "@secondlayer/shared/db/queries/subscriptions";
|
|
946
|
+
import { sql as sql2 } from "kysely";
|
|
947
|
+
|
|
948
|
+
// src/runtime/emitter-matcher.ts
|
|
949
|
+
function isPrimitive(v) {
|
|
950
|
+
const t = typeof v;
|
|
951
|
+
return t === "string" || t === "number" || t === "boolean";
|
|
952
|
+
}
|
|
953
|
+
function coerceNumeric(v) {
|
|
954
|
+
if (typeof v === "number" && Number.isFinite(v))
|
|
955
|
+
return v;
|
|
956
|
+
if (typeof v === "bigint")
|
|
957
|
+
return Number(v);
|
|
958
|
+
if (typeof v === "string" && v !== "" && !Number.isNaN(Number(v))) {
|
|
959
|
+
return Number(v);
|
|
960
|
+
}
|
|
961
|
+
return null;
|
|
962
|
+
}
|
|
963
|
+
function matchClause(rowValue, clause) {
|
|
964
|
+
if (isPrimitive(clause)) {
|
|
965
|
+
if (typeof clause === "number" || typeof rowValue === "number") {
|
|
966
|
+
const a = coerceNumeric(rowValue);
|
|
967
|
+
const b = coerceNumeric(clause);
|
|
968
|
+
if (a !== null && b !== null)
|
|
969
|
+
return a === b;
|
|
970
|
+
}
|
|
971
|
+
return rowValue === clause || String(rowValue) === String(clause);
|
|
972
|
+
}
|
|
973
|
+
if (clause === null || typeof clause !== "object" || Array.isArray(clause)) {
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
const keys = Object.keys(clause);
|
|
977
|
+
if (keys.length !== 1)
|
|
978
|
+
return false;
|
|
979
|
+
const op = keys[0];
|
|
980
|
+
const c = clause;
|
|
981
|
+
switch (op) {
|
|
982
|
+
case "eq":
|
|
983
|
+
return matchClause(rowValue, c.eq);
|
|
984
|
+
case "neq":
|
|
985
|
+
return !matchClause(rowValue, c.neq);
|
|
986
|
+
case "gt":
|
|
987
|
+
case "gte":
|
|
988
|
+
case "lt":
|
|
989
|
+
case "lte": {
|
|
990
|
+
const a = coerceNumeric(rowValue);
|
|
991
|
+
const b = coerceNumeric(c[op]);
|
|
992
|
+
if (a === null || b === null)
|
|
993
|
+
return false;
|
|
994
|
+
if (op === "gt")
|
|
995
|
+
return a > b;
|
|
996
|
+
if (op === "gte")
|
|
997
|
+
return a >= b;
|
|
998
|
+
if (op === "lt")
|
|
999
|
+
return a < b;
|
|
1000
|
+
return a <= b;
|
|
1001
|
+
}
|
|
1002
|
+
case "in": {
|
|
1003
|
+
const list = c.in;
|
|
1004
|
+
if (!Array.isArray(list))
|
|
1005
|
+
return false;
|
|
1006
|
+
return list.some((item) => isPrimitive(item) && matchClause(rowValue, item));
|
|
1007
|
+
}
|
|
1008
|
+
default:
|
|
1009
|
+
return false;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
function matchesFilter(filter, row) {
|
|
1013
|
+
if (!filter || Object.keys(filter).length === 0)
|
|
1014
|
+
return true;
|
|
1015
|
+
for (const [col, clause] of Object.entries(filter)) {
|
|
1016
|
+
if (!matchClause(row[col], clause))
|
|
1017
|
+
return false;
|
|
1018
|
+
}
|
|
1019
|
+
return true;
|
|
1020
|
+
}
|
|
1021
|
+
function key(subgraphName, tableName) {
|
|
1022
|
+
return `${subgraphName}\x00${tableName}`;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
class SubscriptionMatcher {
|
|
1026
|
+
byKey = new Map;
|
|
1027
|
+
byId = new Map;
|
|
1028
|
+
setAll(subs) {
|
|
1029
|
+
this.byKey.clear();
|
|
1030
|
+
this.byId.clear();
|
|
1031
|
+
for (const sub of subs) {
|
|
1032
|
+
if (sub.status !== "active")
|
|
1033
|
+
continue;
|
|
1034
|
+
this.byId.set(sub.id, sub);
|
|
1035
|
+
const k = key(sub.subgraph_name, sub.table_name);
|
|
1036
|
+
const arr = this.byKey.get(k);
|
|
1037
|
+
if (arr)
|
|
1038
|
+
arr.push(sub);
|
|
1039
|
+
else
|
|
1040
|
+
this.byKey.set(k, [sub]);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
match(subgraphName, tableName, row) {
|
|
1044
|
+
const bucket = this.byKey.get(key(subgraphName, tableName));
|
|
1045
|
+
if (!bucket)
|
|
1046
|
+
return [];
|
|
1047
|
+
const hits = [];
|
|
1048
|
+
for (const sub of bucket) {
|
|
1049
|
+
if (matchesFilter(sub.filter, row))
|
|
1050
|
+
hits.push(sub);
|
|
1051
|
+
}
|
|
1052
|
+
return hits;
|
|
1053
|
+
}
|
|
1054
|
+
has(subgraphName, tableName) {
|
|
1055
|
+
return this.byKey.has(key(subgraphName, tableName));
|
|
1056
|
+
}
|
|
1057
|
+
size() {
|
|
1058
|
+
return this.byId.size;
|
|
1059
|
+
}
|
|
1060
|
+
get(id) {
|
|
1061
|
+
return this.byId.get(id);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// src/runtime/subscription-state.ts
|
|
1066
|
+
var matcher = new SubscriptionMatcher;
|
|
1067
|
+
async function refreshMatcher(db) {
|
|
1068
|
+
const rows = await sql2`
|
|
1069
|
+
SELECT * FROM subscriptions WHERE status = 'active'
|
|
1070
|
+
`.execute(db);
|
|
1071
|
+
matcher.setAll(rows.rows);
|
|
1072
|
+
return matcher.size();
|
|
1073
|
+
}
|
|
1074
|
+
|
|
866
1075
|
// src/runtime/block-processor.ts
|
|
867
1076
|
var schemaNameCache = new Map;
|
|
868
1077
|
async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
@@ -886,7 +1095,7 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
886
1095
|
} else {
|
|
887
1096
|
block = await sourceDb.selectFrom("blocks").selectAll().where("height", "=", blockHeight).executeTakeFirst();
|
|
888
1097
|
if (!block) {
|
|
889
|
-
|
|
1098
|
+
logger4.warn("Block not found for subgraph processing", {
|
|
890
1099
|
subgraph: subgraphName,
|
|
891
1100
|
blockHeight
|
|
892
1101
|
});
|
|
@@ -894,7 +1103,7 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
894
1103
|
return result;
|
|
895
1104
|
}
|
|
896
1105
|
if (!block.canonical) {
|
|
897
|
-
|
|
1106
|
+
logger4.debug("Skipping non-canonical block", {
|
|
898
1107
|
subgraph: subgraphName,
|
|
899
1108
|
blockHeight
|
|
900
1109
|
});
|
|
@@ -941,7 +1150,10 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
941
1150
|
result.errors = runResult.errors;
|
|
942
1151
|
if (ctx.pendingOps > 0) {
|
|
943
1152
|
const flushStart = performance.now();
|
|
944
|
-
await ctx.flush();
|
|
1153
|
+
const manifest = await ctx.flush();
|
|
1154
|
+
if (manifest.count > 0) {
|
|
1155
|
+
await emitSubscriptionOutbox(tx, subgraphName, manifest, matcher, block.height);
|
|
1156
|
+
}
|
|
945
1157
|
flushMs = performance.now() - flushStart;
|
|
946
1158
|
}
|
|
947
1159
|
if (!opts?.skipProgressUpdate) {
|
|
@@ -963,10 +1175,10 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
963
1175
|
try {
|
|
964
1176
|
const tables = Object.keys(subgraph.schema);
|
|
965
1177
|
for (const table of tables) {
|
|
966
|
-
const { rows } = await
|
|
1178
|
+
const { rows } = await sql3.raw(`SELECT n_live_tup AS count FROM pg_stat_user_tables WHERE schemaname = '${schemaName}' AND relname = '${table}'`).execute(targetDb);
|
|
967
1179
|
const count = Number(rows[0]?.count ?? 0);
|
|
968
1180
|
if (count >= 1e7) {
|
|
969
|
-
|
|
1181
|
+
logger4.warn("Subgraph table exceeds 10M rows (estimate)", {
|
|
970
1182
|
subgraph: subgraphName,
|
|
971
1183
|
table,
|
|
972
1184
|
count
|
|
@@ -1052,7 +1264,7 @@ import {
|
|
|
1052
1264
|
recordSubgraphProcessed as recordSubgraphProcessed2,
|
|
1053
1265
|
updateSubgraphStatus as updateSubgraphStatus2
|
|
1054
1266
|
} from "@secondlayer/shared/db/queries/subgraphs";
|
|
1055
|
-
import { logger as
|
|
1267
|
+
import { logger as logger5 } from "@secondlayer/shared/logger";
|
|
1056
1268
|
|
|
1057
1269
|
// src/schema/generator.ts
|
|
1058
1270
|
var TYPE_MAP = {
|
|
@@ -1225,7 +1437,7 @@ async function processBlockRange(def, opts) {
|
|
|
1225
1437
|
while (currentHeight <= toBlock) {
|
|
1226
1438
|
if (opts.signal?.aborted) {
|
|
1227
1439
|
aborted = true;
|
|
1228
|
-
|
|
1440
|
+
logger5.info("Block processing aborted", {
|
|
1229
1441
|
subgraph: subgraphName,
|
|
1230
1442
|
currentBlock: currentHeight,
|
|
1231
1443
|
reason: String(opts.signal.reason ?? "unknown")
|
|
@@ -1255,7 +1467,7 @@ async function processBlockRange(def, opts) {
|
|
|
1255
1467
|
});
|
|
1256
1468
|
} catch (err) {
|
|
1257
1469
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
1258
|
-
|
|
1470
|
+
logger5.error("Block processing error", {
|
|
1259
1471
|
subgraph: subgraphName,
|
|
1260
1472
|
blockHeight: height,
|
|
1261
1473
|
error: errorMsg
|
|
@@ -1280,7 +1492,7 @@ async function processBlockRange(def, opts) {
|
|
|
1280
1492
|
await updateSubgraphStatus2(targetDb, subgraphName, status, height);
|
|
1281
1493
|
}
|
|
1282
1494
|
if (blocksProcessed % LOG_INTERVAL === 0) {
|
|
1283
|
-
|
|
1495
|
+
logger5.info(`${status === "reindexing" ? "Reindex" : "Backfill"} progress`, {
|
|
1284
1496
|
subgraph: subgraphName,
|
|
1285
1497
|
processed: blocksProcessed,
|
|
1286
1498
|
total: totalBlocks,
|
|
@@ -1292,7 +1504,7 @@ async function processBlockRange(def, opts) {
|
|
|
1292
1504
|
if (batchFailedBlocks.length > 0 && opts.subgraphId) {
|
|
1293
1505
|
const gaps = coalesceFailedBlocks(batchFailedBlocks);
|
|
1294
1506
|
await recordGapBatch(targetDb, opts.subgraphId, subgraphName, gaps).catch((err) => {
|
|
1295
|
-
|
|
1507
|
+
logger5.warn("Failed to record subgraph gaps", {
|
|
1296
1508
|
subgraph: subgraphName,
|
|
1297
1509
|
error: err instanceof Error ? err.message : String(err)
|
|
1298
1510
|
});
|
|
@@ -1329,11 +1541,11 @@ async function reindexSubgraph(def, opts) {
|
|
|
1329
1541
|
const subgraphName = def.name;
|
|
1330
1542
|
const schemaName = opts?.schemaName ?? pgSchemaName(subgraphName);
|
|
1331
1543
|
await updateSubgraphStatus2(targetDb, subgraphName, "reindexing");
|
|
1332
|
-
|
|
1544
|
+
logger5.info("Reindex starting", { subgraph: subgraphName });
|
|
1333
1545
|
try {
|
|
1334
1546
|
const { fromBlock, toBlock } = await resolveBlockRange(sourceDb, def, opts);
|
|
1335
1547
|
if (fromBlock > toBlock) {
|
|
1336
|
-
|
|
1548
|
+
logger5.info("No blocks to reindex", {
|
|
1337
1549
|
subgraph: subgraphName,
|
|
1338
1550
|
fromBlock,
|
|
1339
1551
|
toBlock
|
|
@@ -1347,8 +1559,8 @@ async function reindexSubgraph(def, opts) {
|
|
|
1347
1559
|
for (const stmt of statements) {
|
|
1348
1560
|
await client.unsafe(stmt);
|
|
1349
1561
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1562
|
+
logger5.info("Schema recreated for reindex", { subgraph: subgraphName });
|
|
1563
|
+
logger5.info("Reindexing blocks", {
|
|
1352
1564
|
subgraph: subgraphName,
|
|
1353
1565
|
fromBlock,
|
|
1354
1566
|
toBlock,
|
|
@@ -1369,9 +1581,9 @@ async function reindexSubgraph(def, opts) {
|
|
|
1369
1581
|
if (reason === "user-cancelled") {
|
|
1370
1582
|
await updateSubgraphStatus2(targetDb, subgraphName, "active");
|
|
1371
1583
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
1372
|
-
|
|
1584
|
+
logger5.info("Reindex cancelled by user", { subgraph: subgraphName });
|
|
1373
1585
|
} else {
|
|
1374
|
-
|
|
1586
|
+
logger5.info("Reindex interrupted by shutdown, will resume", {
|
|
1375
1587
|
subgraph: subgraphName
|
|
1376
1588
|
});
|
|
1377
1589
|
}
|
|
@@ -1383,7 +1595,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
1383
1595
|
}
|
|
1384
1596
|
await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
|
|
1385
1597
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
1386
|
-
|
|
1598
|
+
logger5.info("Reindex complete", {
|
|
1387
1599
|
subgraph: subgraphName,
|
|
1388
1600
|
blocks: result.blocksProcessed,
|
|
1389
1601
|
events: result.totalEventsProcessed,
|
|
@@ -1391,7 +1603,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
1391
1603
|
});
|
|
1392
1604
|
return { processed: result.blocksProcessed };
|
|
1393
1605
|
} catch (err) {
|
|
1394
|
-
|
|
1606
|
+
logger5.error("Reindex failed", {
|
|
1395
1607
|
subgraph: subgraphName,
|
|
1396
1608
|
error: getErrorMessage2(err)
|
|
1397
1609
|
});
|
|
@@ -1411,7 +1623,7 @@ async function resumeReindex(def, opts) {
|
|
|
1411
1623
|
if (!row)
|
|
1412
1624
|
throw new Error(`Subgraph "${subgraphName}" not found`);
|
|
1413
1625
|
if (row.reindex_from_block == null || row.reindex_to_block == null) {
|
|
1414
|
-
|
|
1626
|
+
logger5.info("No reindex metadata, starting fresh reindex", {
|
|
1415
1627
|
subgraph: subgraphName
|
|
1416
1628
|
});
|
|
1417
1629
|
return reindexSubgraph(def, {
|
|
@@ -1422,12 +1634,12 @@ async function resumeReindex(def, opts) {
|
|
|
1422
1634
|
const fromBlock = Math.max(row.last_processed_block + 1, row.reindex_from_block);
|
|
1423
1635
|
const toBlock = row.reindex_to_block;
|
|
1424
1636
|
if (fromBlock > toBlock) {
|
|
1425
|
-
|
|
1637
|
+
logger5.info("Resume: no remaining blocks", { subgraph: subgraphName });
|
|
1426
1638
|
await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
|
|
1427
1639
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
1428
1640
|
return { processed: 0 };
|
|
1429
1641
|
}
|
|
1430
|
-
|
|
1642
|
+
logger5.info("Resuming reindex", {
|
|
1431
1643
|
subgraph: subgraphName,
|
|
1432
1644
|
fromBlock,
|
|
1433
1645
|
toBlock,
|
|
@@ -1448,9 +1660,9 @@ async function resumeReindex(def, opts) {
|
|
|
1448
1660
|
if (reason === "user-cancelled") {
|
|
1449
1661
|
await updateSubgraphStatus2(targetDb, subgraphName, "active");
|
|
1450
1662
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
1451
|
-
|
|
1663
|
+
logger5.info("Resume cancelled by user", { subgraph: subgraphName });
|
|
1452
1664
|
} else {
|
|
1453
|
-
|
|
1665
|
+
logger5.info("Resume interrupted by shutdown, will resume again", {
|
|
1454
1666
|
subgraph: subgraphName
|
|
1455
1667
|
});
|
|
1456
1668
|
}
|
|
@@ -1462,13 +1674,13 @@ async function resumeReindex(def, opts) {
|
|
|
1462
1674
|
}
|
|
1463
1675
|
await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
|
|
1464
1676
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
1465
|
-
|
|
1677
|
+
logger5.info("Resumed reindex complete", {
|
|
1466
1678
|
subgraph: subgraphName,
|
|
1467
1679
|
blocks: result.blocksProcessed
|
|
1468
1680
|
});
|
|
1469
1681
|
return { processed: result.blocksProcessed };
|
|
1470
1682
|
} catch (err) {
|
|
1471
|
-
|
|
1683
|
+
logger5.error("Resumed reindex failed", {
|
|
1472
1684
|
subgraph: subgraphName,
|
|
1473
1685
|
error: getErrorMessage2(err)
|
|
1474
1686
|
});
|
|
@@ -1479,7 +1691,7 @@ async function resumeReindex(def, opts) {
|
|
|
1479
1691
|
async function backfillSubgraph(def, opts) {
|
|
1480
1692
|
const targetDb = getTargetDb2();
|
|
1481
1693
|
const subgraphName = def.name;
|
|
1482
|
-
|
|
1694
|
+
logger5.info("Backfill starting", {
|
|
1483
1695
|
subgraph: subgraphName,
|
|
1484
1696
|
from: opts.fromBlock,
|
|
1485
1697
|
to: opts.toBlock
|
|
@@ -1496,12 +1708,12 @@ async function backfillSubgraph(def, opts) {
|
|
|
1496
1708
|
signal: opts.signal
|
|
1497
1709
|
});
|
|
1498
1710
|
if (result.aborted) {
|
|
1499
|
-
|
|
1711
|
+
logger5.info("Backfill aborted", { subgraph: subgraphName });
|
|
1500
1712
|
return { processed: result.blocksProcessed };
|
|
1501
1713
|
}
|
|
1502
1714
|
const resolved = await resolveGaps(targetDb, subgraphName, opts.fromBlock, opts.toBlock).catch(() => 0);
|
|
1503
1715
|
if (resolved > 0) {
|
|
1504
|
-
|
|
1716
|
+
logger5.info("Resolved subgraph gaps via backfill", {
|
|
1505
1717
|
subgraph: subgraphName,
|
|
1506
1718
|
resolved
|
|
1507
1719
|
});
|
|
@@ -1510,7 +1722,7 @@ async function backfillSubgraph(def, opts) {
|
|
|
1510
1722
|
if (result.totalEventsProcessed > 0 || result.totalErrors > 0) {
|
|
1511
1723
|
await recordSubgraphProcessed3(targetDb, subgraphName, result.totalEventsProcessed, result.totalErrors, result.totalErrors > 0 ? `${result.totalErrors} error(s) during backfill` : undefined);
|
|
1512
1724
|
}
|
|
1513
|
-
|
|
1725
|
+
logger5.info("Backfill complete", {
|
|
1514
1726
|
subgraph: subgraphName,
|
|
1515
1727
|
blocks: result.blocksProcessed,
|
|
1516
1728
|
events: result.totalEventsProcessed,
|
|
@@ -1518,7 +1730,7 @@ async function backfillSubgraph(def, opts) {
|
|
|
1518
1730
|
});
|
|
1519
1731
|
return { processed: result.blocksProcessed };
|
|
1520
1732
|
} catch (err) {
|
|
1521
|
-
|
|
1733
|
+
logger5.error("Backfill failed", {
|
|
1522
1734
|
subgraph: subgraphName,
|
|
1523
1735
|
error: getErrorMessage2(err)
|
|
1524
1736
|
});
|
|
@@ -1531,5 +1743,5 @@ export {
|
|
|
1531
1743
|
backfillSubgraph
|
|
1532
1744
|
};
|
|
1533
1745
|
|
|
1534
|
-
//# debugId=
|
|
1746
|
+
//# debugId=A2112359A7EA0BBD64756E2164756E21
|
|
1535
1747
|
//# sourceMappingURL=reindex.js.map
|