@secondlayer/subgraphs 0.5.7 → 0.6.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/dist/src/index.d.ts +16 -4
- package/dist/src/index.js +259 -95
- package/dist/src/index.js.map +8 -7
- package/dist/src/runtime/block-processor.d.ts +9 -1
- package/dist/src/runtime/block-processor.js +89 -47
- package/dist/src/runtime/block-processor.js.map +4 -4
- package/dist/src/runtime/catchup.d.ts +2 -2
- package/dist/src/runtime/catchup.js +194 -63
- package/dist/src/runtime/catchup.js.map +7 -6
- package/dist/src/runtime/context.d.ts +3 -1
- package/dist/src/runtime/context.js +63 -33
- package/dist/src/runtime/context.js.map +3 -3
- package/dist/src/runtime/processor.js +194 -63
- package/dist/src/runtime/processor.js.map +7 -6
- package/dist/src/runtime/reindex.d.ts +13 -1
- package/dist/src/runtime/reindex.js +258 -94
- package/dist/src/runtime/reindex.js.map +8 -7
- package/dist/src/runtime/reorg.js +89 -47
- package/dist/src/runtime/reorg.js.map +4 -4
- package/dist/src/runtime/runner.d.ts +3 -1
- package/dist/src/schema/index.js +2 -2
- package/dist/src/schema/index.js.map +3 -3
- package/dist/src/service.js +194 -63
- package/dist/src/service.js.map +7 -6
- package/dist/src/validate.js +2 -2
- package/dist/src/validate.js.map +3 -3
- package/package.json +2 -2
|
@@ -81,4 +81,16 @@ interface ReindexOptions {
|
|
|
81
81
|
declare function reindexSubgraph(def: SubgraphDefinition, opts?: ReindexOptions): Promise<{
|
|
82
82
|
processed: number
|
|
83
83
|
}>;
|
|
84
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Backfill a subgraph by re-processing a block range WITHOUT dropping the schema.
|
|
86
|
+
* Uses upserts so existing data is updated, not duplicated. Safe to run while
|
|
87
|
+
* the subgraph is actively syncing.
|
|
88
|
+
*/
|
|
89
|
+
declare function backfillSubgraph(def: SubgraphDefinition, opts: {
|
|
90
|
+
fromBlock: number
|
|
91
|
+
toBlock: number
|
|
92
|
+
schemaName?: string
|
|
93
|
+
}): Promise<{
|
|
94
|
+
processed: number
|
|
95
|
+
}>;
|
|
96
|
+
export { reindexSubgraph, backfillSubgraph, ReindexOptions };
|
|
@@ -122,53 +122,83 @@ class SubgraphContext {
|
|
|
122
122
|
}
|
|
123
123
|
return opsToFlush.length;
|
|
124
124
|
}
|
|
125
|
+
prepareInsert(op) {
|
|
126
|
+
const upsertKeys = op.data._upsert_keys;
|
|
127
|
+
const data = { ...op.data };
|
|
128
|
+
delete data._upsert_keys;
|
|
129
|
+
delete data._upsert_fallback_keys;
|
|
130
|
+
delete data._upsert_fallback_set;
|
|
131
|
+
data._block_height = this.block.height;
|
|
132
|
+
data._tx_id = this._tx.txId;
|
|
133
|
+
data._created_at = "NOW()";
|
|
134
|
+
const cols = Object.keys(data);
|
|
135
|
+
cols.forEach(validateColumnName);
|
|
136
|
+
const vals = cols.map((c) => data[c] === "NOW()" ? "NOW()" : escapeLiteral(data[c]));
|
|
137
|
+
const batchKey = `${op.table}:${[...cols].sort().join(",")}:${upsertKeys ? [...upsertKeys].sort().join(",") : ""}`;
|
|
138
|
+
return { data, cols, vals, upsertKeys, batchKey };
|
|
139
|
+
}
|
|
125
140
|
buildStatements(ops) {
|
|
126
141
|
const statements = [];
|
|
142
|
+
let currentBatch = null;
|
|
143
|
+
let currentBatchKey = "";
|
|
144
|
+
const flushInsertBatch = () => {
|
|
145
|
+
if (!currentBatch)
|
|
146
|
+
return;
|
|
147
|
+
const qualifiedTable = `"${this.pgSchemaName}"."${currentBatch.table}"`;
|
|
148
|
+
const colList = currentBatch.cols.map((c) => `"${c}"`).join(", ");
|
|
149
|
+
let rows = currentBatch.rows;
|
|
150
|
+
if (currentBatch.upsertKeys && currentBatch.upsertKeys.length > 0) {
|
|
151
|
+
const keyIndices = currentBatch.upsertKeys.map((k) => currentBatch.cols.indexOf(k));
|
|
152
|
+
const seen = new Map;
|
|
153
|
+
for (let i = 0;i < rows.length; i++) {
|
|
154
|
+
const key = keyIndices.map((ki) => rows[i][ki]).join("\x00");
|
|
155
|
+
seen.set(key, i);
|
|
156
|
+
}
|
|
157
|
+
if (seen.size < rows.length) {
|
|
158
|
+
rows = Array.from(seen.values()).map((i) => rows[i]);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const valuesList = rows.map((r) => `(${r.join(", ")})`).join(", ");
|
|
162
|
+
let stmt = `INSERT INTO ${qualifiedTable} (${colList}) VALUES ${valuesList}`;
|
|
163
|
+
if (currentBatch.upsertKeys && currentBatch.upsertKeys.length > 0) {
|
|
164
|
+
const updateCols = currentBatch.cols.filter((c) => !currentBatch.upsertKeys.includes(c) && !c.startsWith("_"));
|
|
165
|
+
if (updateCols.length > 0) {
|
|
166
|
+
const setClauses = updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`);
|
|
167
|
+
stmt += ` ON CONFLICT (${currentBatch.upsertKeys.map((k) => `"${k}"`).join(", ")}) DO UPDATE SET ${setClauses.join(", ")}`;
|
|
168
|
+
} else {
|
|
169
|
+
stmt += ` ON CONFLICT (${currentBatch.upsertKeys.map((k) => `"${k}"`).join(", ")}) DO NOTHING`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
statements.push(stmt);
|
|
173
|
+
currentBatch = null;
|
|
174
|
+
currentBatchKey = "";
|
|
175
|
+
};
|
|
127
176
|
for (const op of ops) {
|
|
128
177
|
const qualifiedTable = `"${this.pgSchemaName}"."${op.table}"`;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
delete data._upsert_fallback_set;
|
|
138
|
-
data._block_height = this.block.height;
|
|
139
|
-
data._tx_id = this._tx.txId;
|
|
140
|
-
data._created_at = "NOW()";
|
|
141
|
-
const cols = Object.keys(data);
|
|
142
|
-
cols.forEach(validateColumnName);
|
|
143
|
-
const vals = cols.map((c) => data[c] === "NOW()" ? "NOW()" : escapeLiteral(data[c]));
|
|
144
|
-
let stmt = `INSERT INTO ${qualifiedTable} (${cols.map((c) => `"${c}"`).join(", ")}) VALUES (${vals.join(", ")})`;
|
|
145
|
-
if (upsertKeys && upsertKeys.length > 0) {
|
|
146
|
-
const updateCols = cols.filter((c) => !upsertKeys.includes(c) && !c.startsWith("_"));
|
|
147
|
-
if (updateCols.length > 0) {
|
|
148
|
-
const setClauses = updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`);
|
|
149
|
-
stmt += ` ON CONFLICT (${upsertKeys.map((k) => `"${k}"`).join(", ")}) DO UPDATE SET ${setClauses.join(", ")}`;
|
|
150
|
-
} else {
|
|
151
|
-
stmt += ` ON CONFLICT (${upsertKeys.map((k) => `"${k}"`).join(", ")}) DO NOTHING`;
|
|
152
|
-
}
|
|
153
|
-
} else if (fallbackKeys && fallbackSet) {}
|
|
154
|
-
statements.push(stmt);
|
|
155
|
-
break;
|
|
178
|
+
if (op.kind === "insert") {
|
|
179
|
+
const { cols, vals, upsertKeys, batchKey } = this.prepareInsert(op);
|
|
180
|
+
if (batchKey === currentBatchKey && currentBatch) {
|
|
181
|
+
currentBatch.rows.push(vals);
|
|
182
|
+
} else {
|
|
183
|
+
flushInsertBatch();
|
|
184
|
+
currentBatch = { table: op.table, cols, rows: [vals], upsertKeys };
|
|
185
|
+
currentBatchKey = batchKey;
|
|
156
186
|
}
|
|
157
|
-
|
|
187
|
+
} else {
|
|
188
|
+
flushInsertBatch();
|
|
189
|
+
if (op.kind === "update") {
|
|
158
190
|
const setEntries = Object.entries(op.set);
|
|
159
191
|
setEntries.forEach(([k]) => validateColumnName(k));
|
|
160
192
|
const setClauses = setEntries.map(([k, v]) => `"${k}" = ${escapeLiteral(v)}`);
|
|
161
193
|
const { clause } = buildWhereClause(op.data);
|
|
162
194
|
statements.push(`UPDATE ${qualifiedTable} SET ${setClauses.join(", ")} WHERE ${clause}`);
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
case "delete": {
|
|
195
|
+
} else if (op.kind === "delete") {
|
|
166
196
|
const { clause } = buildWhereClause(op.data);
|
|
167
197
|
statements.push(`DELETE FROM ${qualifiedTable} WHERE ${clause}`);
|
|
168
|
-
break;
|
|
169
198
|
}
|
|
170
199
|
}
|
|
171
200
|
}
|
|
201
|
+
flushInsertBatch();
|
|
172
202
|
return statements;
|
|
173
203
|
}
|
|
174
204
|
validateTable(table) {
|
|
@@ -418,6 +448,7 @@ import { updateSubgraphStatus, recordSubgraphProcessed } from "@secondlayer/shar
|
|
|
418
448
|
import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
|
|
419
449
|
|
|
420
450
|
// src/runtime/block-processor.ts
|
|
451
|
+
var schemaNameCache = new Map;
|
|
421
452
|
async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
422
453
|
const db = getDb();
|
|
423
454
|
const blockStart = performance.now();
|
|
@@ -428,19 +459,26 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
428
459
|
errors: 0,
|
|
429
460
|
skipped: false
|
|
430
461
|
};
|
|
431
|
-
|
|
432
|
-
if (
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
462
|
+
let block, txs, evts;
|
|
463
|
+
if (opts?.preloaded) {
|
|
464
|
+
block = opts.preloaded.block;
|
|
465
|
+
txs = opts.preloaded.txs;
|
|
466
|
+
evts = opts.preloaded.events;
|
|
467
|
+
} else {
|
|
468
|
+
block = await db.selectFrom("blocks").selectAll().where("height", "=", blockHeight).executeTakeFirst();
|
|
469
|
+
if (!block) {
|
|
470
|
+
logger3.warn("Block not found for subgraph processing", { subgraph: subgraphName, blockHeight });
|
|
471
|
+
result.skipped = true;
|
|
472
|
+
return result;
|
|
473
|
+
}
|
|
474
|
+
if (!block.canonical) {
|
|
475
|
+
logger3.debug("Skipping non-canonical block", { subgraph: subgraphName, blockHeight });
|
|
476
|
+
result.skipped = true;
|
|
477
|
+
return result;
|
|
478
|
+
}
|
|
479
|
+
txs = await db.selectFrom("transactions").selectAll().where("block_height", "=", blockHeight).execute();
|
|
480
|
+
evts = await db.selectFrom("events").selectAll().where("block_height", "=", blockHeight).execute();
|
|
441
481
|
}
|
|
442
|
-
const txs = await db.selectFrom("transactions").selectAll().where("block_height", "=", blockHeight).execute();
|
|
443
|
-
const evts = await db.selectFrom("events").selectAll().where("block_height", "=", blockHeight).execute();
|
|
444
482
|
const matched = matchSources(subgraph.sources, txs, evts);
|
|
445
483
|
result.matched = matched.length;
|
|
446
484
|
if (matched.length === 0) {
|
|
@@ -449,8 +487,12 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
449
487
|
}
|
|
450
488
|
return result;
|
|
451
489
|
}
|
|
452
|
-
|
|
453
|
-
|
|
490
|
+
let schemaName = schemaNameCache.get(subgraphName);
|
|
491
|
+
if (!schemaName) {
|
|
492
|
+
const subgraphRecord = await db.selectFrom("subgraphs").select("schema_name").where("name", "=", subgraphName).executeTakeFirst();
|
|
493
|
+
schemaName = subgraphRecord?.schema_name ?? pgSchemaName(subgraphName);
|
|
494
|
+
schemaNameCache.set(subgraphName, schemaName);
|
|
495
|
+
}
|
|
454
496
|
const blockMeta = {
|
|
455
497
|
height: block.height,
|
|
456
498
|
hash: block.hash,
|
|
@@ -665,45 +707,96 @@ function generateSubgraphSQL(def, schemaNameOverride) {
|
|
|
665
707
|
return { statements, hash };
|
|
666
708
|
}
|
|
667
709
|
|
|
710
|
+
// src/runtime/batch-loader.ts
|
|
711
|
+
async function loadBlockRange(db, fromHeight, toHeight) {
|
|
712
|
+
const [blocks, txs, events] = await Promise.all([
|
|
713
|
+
db.selectFrom("blocks").selectAll().where("height", ">=", fromHeight).where("height", "<=", toHeight).where("canonical", "=", true).execute(),
|
|
714
|
+
db.selectFrom("transactions").selectAll().where("block_height", ">=", fromHeight).where("block_height", "<=", toHeight).execute(),
|
|
715
|
+
db.selectFrom("events").selectAll().where("block_height", ">=", fromHeight).where("block_height", "<=", toHeight).execute()
|
|
716
|
+
]);
|
|
717
|
+
const txsByHeight = new Map;
|
|
718
|
+
for (const tx of txs) {
|
|
719
|
+
const h = Number(tx.block_height);
|
|
720
|
+
const list = txsByHeight.get(h) ?? [];
|
|
721
|
+
list.push(tx);
|
|
722
|
+
txsByHeight.set(h, list);
|
|
723
|
+
}
|
|
724
|
+
const eventsByHeight = new Map;
|
|
725
|
+
for (const evt of events) {
|
|
726
|
+
const h = Number(evt.block_height);
|
|
727
|
+
const list = eventsByHeight.get(h) ?? [];
|
|
728
|
+
list.push(evt);
|
|
729
|
+
eventsByHeight.set(h, list);
|
|
730
|
+
}
|
|
731
|
+
const result = new Map;
|
|
732
|
+
for (const block of blocks) {
|
|
733
|
+
const h = Number(block.height);
|
|
734
|
+
result.set(h, {
|
|
735
|
+
block,
|
|
736
|
+
txs: txsByHeight.get(h) ?? [],
|
|
737
|
+
events: eventsByHeight.get(h) ?? []
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
return result;
|
|
741
|
+
}
|
|
742
|
+
function avgEventsPerBlock(batch) {
|
|
743
|
+
if (batch.size === 0)
|
|
744
|
+
return 0;
|
|
745
|
+
let totalEvents = 0;
|
|
746
|
+
for (const data of batch.values()) {
|
|
747
|
+
totalEvents += data.events.length;
|
|
748
|
+
}
|
|
749
|
+
return totalEvents / batch.size;
|
|
750
|
+
}
|
|
751
|
+
|
|
668
752
|
// src/runtime/reindex.ts
|
|
669
753
|
var LOG_INTERVAL = 1000;
|
|
670
|
-
|
|
754
|
+
var DEFAULT_BATCH_SIZE = 500;
|
|
755
|
+
var MIN_BATCH_SIZE = 100;
|
|
756
|
+
var MAX_BATCH_SIZE = 1000;
|
|
757
|
+
async function processBlockRange(def, opts) {
|
|
671
758
|
const db = getDb2();
|
|
672
|
-
const client = getRawClient();
|
|
673
759
|
const subgraphName = def.name;
|
|
674
|
-
const
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
760
|
+
const { fromBlock, toBlock, status } = opts;
|
|
761
|
+
const totalBlocks = toBlock - fromBlock + 1;
|
|
762
|
+
const stats = new StatsAccumulator(subgraphName, opts.apiKeyId, opts.isCatchup);
|
|
763
|
+
let blocksProcessed = 0;
|
|
764
|
+
let totalEventsProcessed = 0;
|
|
765
|
+
let totalErrors = 0;
|
|
766
|
+
let batchSize = DEFAULT_BATCH_SIZE;
|
|
767
|
+
let currentHeight = fromBlock;
|
|
768
|
+
let nextBatchPromise = loadBlockRange(db, currentHeight, Math.min(currentHeight + batchSize - 1, toBlock));
|
|
769
|
+
while (currentHeight <= toBlock) {
|
|
770
|
+
const batch = await nextBatchPromise;
|
|
771
|
+
const batchEnd = Math.min(currentHeight + batchSize - 1, toBlock);
|
|
772
|
+
const nextStart = batchEnd + 1;
|
|
773
|
+
if (nextStart <= toBlock) {
|
|
774
|
+
const nextEnd = Math.min(nextStart + batchSize - 1, toBlock);
|
|
775
|
+
nextBatchPromise = loadBlockRange(db, nextStart, nextEnd);
|
|
682
776
|
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
const result = await processBlock(def, subgraphName, height, { skipProgressUpdate: true });
|
|
777
|
+
for (let height = currentHeight;height <= batchEnd; height++) {
|
|
778
|
+
const blockData = batch.get(height);
|
|
779
|
+
if (!blockData) {
|
|
780
|
+
blocksProcessed++;
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
let result;
|
|
784
|
+
try {
|
|
785
|
+
result = await processBlock(def, subgraphName, height, {
|
|
786
|
+
skipProgressUpdate: true,
|
|
787
|
+
preloaded: blockData
|
|
788
|
+
});
|
|
789
|
+
} catch (err) {
|
|
790
|
+
logger4.error("Block processing error", {
|
|
791
|
+
subgraph: subgraphName,
|
|
792
|
+
blockHeight: height,
|
|
793
|
+
error: err instanceof Error ? err.message : String(err)
|
|
794
|
+
});
|
|
795
|
+
await updateSubgraphStatus2(db, subgraphName, status, height).catch(() => {});
|
|
796
|
+
blocksProcessed++;
|
|
797
|
+
totalErrors++;
|
|
798
|
+
continue;
|
|
799
|
+
}
|
|
707
800
|
blocksProcessed++;
|
|
708
801
|
totalEventsProcessed += result.processed;
|
|
709
802
|
totalErrors += result.errors;
|
|
@@ -713,11 +806,11 @@ async function reindexSubgraph(def, opts) {
|
|
|
713
806
|
await stats.flush(db);
|
|
714
807
|
}
|
|
715
808
|
}
|
|
716
|
-
if (blocksProcessed %
|
|
717
|
-
await updateSubgraphStatus2(db, subgraphName,
|
|
809
|
+
if (blocksProcessed % 100 === 0) {
|
|
810
|
+
await updateSubgraphStatus2(db, subgraphName, status, height);
|
|
718
811
|
}
|
|
719
812
|
if (blocksProcessed % LOG_INTERVAL === 0) {
|
|
720
|
-
logger4.info("Reindex
|
|
813
|
+
logger4.info(`${status === "reindexing" ? "Reindex" : "Backfill"} progress`, {
|
|
721
814
|
subgraph: subgraphName,
|
|
722
815
|
processed: blocksProcessed,
|
|
723
816
|
total: totalBlocks,
|
|
@@ -726,26 +819,97 @@ async function reindexSubgraph(def, opts) {
|
|
|
726
819
|
});
|
|
727
820
|
}
|
|
728
821
|
}
|
|
729
|
-
|
|
822
|
+
const avg = avgEventsPerBlock(batch);
|
|
823
|
+
if (avg > 50)
|
|
824
|
+
batchSize = Math.max(Math.round(batchSize * 0.5), MIN_BATCH_SIZE);
|
|
825
|
+
else if (avg < 10)
|
|
826
|
+
batchSize = Math.min(Math.round(batchSize * 1.5), MAX_BATCH_SIZE);
|
|
827
|
+
currentHeight = batchEnd + 1;
|
|
828
|
+
}
|
|
829
|
+
await stats.flush(db);
|
|
830
|
+
return { blocksProcessed, totalEventsProcessed, totalErrors };
|
|
831
|
+
}
|
|
832
|
+
async function resolveBlockRange(db, opts) {
|
|
833
|
+
const fromBlock = opts?.fromBlock ?? 1;
|
|
834
|
+
let toBlock;
|
|
835
|
+
if (opts?.toBlock != null) {
|
|
836
|
+
toBlock = opts.toBlock;
|
|
837
|
+
} else {
|
|
838
|
+
const progress = await db.selectFrom("index_progress").selectAll().where("network", "=", process.env.NETWORK ?? "mainnet").executeTakeFirst();
|
|
839
|
+
toBlock = progress?.last_indexed_block ?? progress?.last_contiguous_block ?? 0;
|
|
840
|
+
}
|
|
841
|
+
return { fromBlock, toBlock };
|
|
842
|
+
}
|
|
843
|
+
async function reindexSubgraph(def, opts) {
|
|
844
|
+
const db = getDb2();
|
|
845
|
+
const client = getRawClient();
|
|
846
|
+
const subgraphName = def.name;
|
|
847
|
+
const schemaName = opts?.schemaName ?? pgSchemaName(subgraphName);
|
|
848
|
+
await updateSubgraphStatus2(db, subgraphName, "reindexing");
|
|
849
|
+
logger4.info("Reindex starting", { subgraph: subgraphName });
|
|
850
|
+
try {
|
|
851
|
+
await client.unsafe(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`);
|
|
852
|
+
const { statements } = generateSubgraphSQL(def, schemaName);
|
|
853
|
+
for (const stmt of statements) {
|
|
854
|
+
await client.unsafe(stmt);
|
|
855
|
+
}
|
|
856
|
+
logger4.info("Schema recreated for reindex", { subgraph: subgraphName });
|
|
857
|
+
const { fromBlock, toBlock } = await resolveBlockRange(db, opts);
|
|
858
|
+
if (fromBlock > toBlock) {
|
|
859
|
+
logger4.info("No blocks to reindex", { subgraph: subgraphName, fromBlock, toBlock });
|
|
860
|
+
await updateSubgraphStatus2(db, subgraphName, "active", 0);
|
|
861
|
+
return { processed: 0 };
|
|
862
|
+
}
|
|
863
|
+
logger4.info("Reindexing blocks", { subgraph: subgraphName, fromBlock, toBlock, totalBlocks: toBlock - fromBlock + 1 });
|
|
864
|
+
const subgraphRow = await db.selectFrom("subgraphs").select("api_key_id").where("name", "=", subgraphName).executeTakeFirst();
|
|
865
|
+
const result = await processBlockRange(def, {
|
|
866
|
+
fromBlock,
|
|
867
|
+
toBlock,
|
|
868
|
+
status: "reindexing",
|
|
869
|
+
isCatchup: false,
|
|
870
|
+
apiKeyId: subgraphRow?.api_key_id ?? null
|
|
871
|
+
});
|
|
730
872
|
const { recordSubgraphProcessed: recordSubgraphProcessed2 } = await import("@secondlayer/shared/db/queries/subgraphs");
|
|
731
|
-
if (totalEventsProcessed > 0 || totalErrors > 0) {
|
|
732
|
-
await recordSubgraphProcessed2(db, subgraphName, totalEventsProcessed, totalErrors, totalErrors > 0 ? `${totalErrors} error(s) during reindex` : undefined);
|
|
873
|
+
if (result.totalEventsProcessed > 0 || result.totalErrors > 0) {
|
|
874
|
+
await recordSubgraphProcessed2(db, subgraphName, result.totalEventsProcessed, result.totalErrors, result.totalErrors > 0 ? `${result.totalErrors} error(s) during reindex` : undefined);
|
|
733
875
|
}
|
|
734
876
|
await updateSubgraphStatus2(db, subgraphName, "active", toBlock);
|
|
735
|
-
logger4.info("Reindex complete", { subgraph: subgraphName, blocks: blocksProcessed, events: totalEventsProcessed, errors: totalErrors });
|
|
736
|
-
return { processed: blocksProcessed };
|
|
877
|
+
logger4.info("Reindex complete", { subgraph: subgraphName, blocks: result.blocksProcessed, events: result.totalEventsProcessed, errors: result.totalErrors });
|
|
878
|
+
return { processed: result.blocksProcessed };
|
|
737
879
|
} catch (err) {
|
|
738
|
-
logger4.error("Reindex failed", {
|
|
739
|
-
subgraph: subgraphName,
|
|
740
|
-
error: getErrorMessage2(err)
|
|
741
|
-
});
|
|
880
|
+
logger4.error("Reindex failed", { subgraph: subgraphName, error: getErrorMessage2(err) });
|
|
742
881
|
await updateSubgraphStatus2(db, subgraphName, "error");
|
|
743
882
|
throw err;
|
|
744
883
|
}
|
|
745
884
|
}
|
|
885
|
+
async function backfillSubgraph(def, opts) {
|
|
886
|
+
const db = getDb2();
|
|
887
|
+
const subgraphName = def.name;
|
|
888
|
+
logger4.info("Backfill starting", { subgraph: subgraphName, from: opts.fromBlock, to: opts.toBlock });
|
|
889
|
+
try {
|
|
890
|
+
const subgraphRow = await db.selectFrom("subgraphs").select("api_key_id").where("name", "=", subgraphName).executeTakeFirst();
|
|
891
|
+
const result = await processBlockRange(def, {
|
|
892
|
+
fromBlock: opts.fromBlock,
|
|
893
|
+
toBlock: opts.toBlock,
|
|
894
|
+
status: "active",
|
|
895
|
+
isCatchup: false,
|
|
896
|
+
apiKeyId: subgraphRow?.api_key_id ?? null
|
|
897
|
+
});
|
|
898
|
+
const { recordSubgraphProcessed: recordSubgraphProcessed2 } = await import("@secondlayer/shared/db/queries/subgraphs");
|
|
899
|
+
if (result.totalEventsProcessed > 0 || result.totalErrors > 0) {
|
|
900
|
+
await recordSubgraphProcessed2(db, subgraphName, result.totalEventsProcessed, result.totalErrors, result.totalErrors > 0 ? `${result.totalErrors} error(s) during backfill` : undefined);
|
|
901
|
+
}
|
|
902
|
+
logger4.info("Backfill complete", { subgraph: subgraphName, blocks: result.blocksProcessed, events: result.totalEventsProcessed, errors: result.totalErrors });
|
|
903
|
+
return { processed: result.blocksProcessed };
|
|
904
|
+
} catch (err) {
|
|
905
|
+
logger4.error("Backfill failed", { subgraph: subgraphName, error: getErrorMessage2(err) });
|
|
906
|
+
throw err;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
746
909
|
export {
|
|
747
|
-
reindexSubgraph
|
|
910
|
+
reindexSubgraph,
|
|
911
|
+
backfillSubgraph
|
|
748
912
|
};
|
|
749
913
|
|
|
750
|
-
//# debugId=
|
|
914
|
+
//# debugId=15F1B59510B2A45164756E2164756E21
|
|
751
915
|
//# sourceMappingURL=reindex.js.map
|