@secondlayer/subgraphs 3.18.0 → 3.19.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.js +87 -31
- package/dist/src/index.js.map +5 -4
- package/dist/src/runtime/processor.js +137 -81
- package/dist/src/runtime/processor.js.map +5 -4
- package/dist/src/runtime/reindex.js +87 -31
- package/dist/src/runtime/reindex.js.map +5 -4
- package/dist/src/service.js +140 -84
- package/dist/src/service.js.map +5 -4
- package/package.json +2 -2
|
@@ -2302,7 +2302,7 @@ class StatsAccumulator {
|
|
|
2302
2302
|
}
|
|
2303
2303
|
|
|
2304
2304
|
// src/runtime/reindex.ts
|
|
2305
|
-
import { getErrorMessage as
|
|
2305
|
+
import { getErrorMessage as getErrorMessage3 } from "@secondlayer/shared";
|
|
2306
2306
|
import { getRawClient, getTargetDb as getTargetDb2 } from "@secondlayer/shared/db";
|
|
2307
2307
|
import {
|
|
2308
2308
|
recordGapBatch,
|
|
@@ -2316,7 +2316,58 @@ import {
|
|
|
2316
2316
|
recordSubgraphProcessed as recordSubgraphProcessed2,
|
|
2317
2317
|
updateSubgraphStatus as updateSubgraphStatus2
|
|
2318
2318
|
} from "@secondlayer/shared/db/queries/subgraphs";
|
|
2319
|
+
import { logger as logger7 } from "@secondlayer/shared/logger";
|
|
2320
|
+
|
|
2321
|
+
// src/runtime/reindex-notify.ts
|
|
2322
|
+
import { getErrorMessage as getErrorMessage2 } from "@secondlayer/shared";
|
|
2319
2323
|
import { logger as logger6 } from "@secondlayer/shared/logger";
|
|
2324
|
+
async function notifyReindexComplete(db, subgraphName, stats) {
|
|
2325
|
+
try {
|
|
2326
|
+
const subgraph = await db.selectFrom("subgraphs").select(["account_id"]).where("name", "=", subgraphName).executeTakeFirst();
|
|
2327
|
+
if (!subgraph)
|
|
2328
|
+
return;
|
|
2329
|
+
const account = await db.selectFrom("accounts").select(["email", "notify_reindex_complete"]).where("id", "=", subgraph.account_id).executeTakeFirst();
|
|
2330
|
+
if (!account?.email || !account.notify_reindex_complete)
|
|
2331
|
+
return;
|
|
2332
|
+
const resendKey = process.env.RESEND_API_KEY;
|
|
2333
|
+
if (!resendKey) {
|
|
2334
|
+
logger6.warn("RESEND_API_KEY unset — skipping reindex-complete email", {
|
|
2335
|
+
subgraph: subgraphName
|
|
2336
|
+
});
|
|
2337
|
+
return;
|
|
2338
|
+
}
|
|
2339
|
+
const from = process.env.EMAIL_FROM ?? "Secondlayer <noreply@secondlayer.tools>";
|
|
2340
|
+
const body = stats.errors > 0 ? `Your subgraph "${subgraphName}" finished reindexing — ${stats.blocks.toLocaleString()} blocks, ${stats.events.toLocaleString()} events, ${stats.errors.toLocaleString()} errors. Check the dashboard for details.` : `Your subgraph "${subgraphName}" finished reindexing — ${stats.blocks.toLocaleString()} blocks, ${stats.events.toLocaleString()} events processed, no errors. It's live now.`;
|
|
2341
|
+
const res = await fetch("https://api.resend.com/emails", {
|
|
2342
|
+
method: "POST",
|
|
2343
|
+
headers: {
|
|
2344
|
+
Authorization: `Bearer ${resendKey}`,
|
|
2345
|
+
"Content-Type": "application/json"
|
|
2346
|
+
},
|
|
2347
|
+
body: JSON.stringify({
|
|
2348
|
+
from,
|
|
2349
|
+
to: [account.email],
|
|
2350
|
+
subject: `Reindex complete: ${subgraphName}`,
|
|
2351
|
+
text: body
|
|
2352
|
+
})
|
|
2353
|
+
});
|
|
2354
|
+
if (!res.ok) {
|
|
2355
|
+
const text = await res.text().catch(() => "");
|
|
2356
|
+
logger6.warn("reindex-complete email failed", {
|
|
2357
|
+
subgraph: subgraphName,
|
|
2358
|
+
status: res.status,
|
|
2359
|
+
body: text.slice(0, 200)
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
2362
|
+
} catch (err) {
|
|
2363
|
+
logger6.warn("reindex-complete email threw", {
|
|
2364
|
+
subgraph: subgraphName,
|
|
2365
|
+
error: getErrorMessage2(err)
|
|
2366
|
+
});
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// src/runtime/reindex.ts
|
|
2320
2371
|
var LOG_INTERVAL = 1000;
|
|
2321
2372
|
var HEALTH_FLUSH_INTERVAL = 1000;
|
|
2322
2373
|
var PROGRESS_FLUSH_INTERVAL_MS = 5000;
|
|
@@ -2421,7 +2472,7 @@ async function processBlockRange(def, opts) {
|
|
|
2421
2472
|
while (currentHeight <= toBlock) {
|
|
2422
2473
|
if (opts.signal?.aborted) {
|
|
2423
2474
|
aborted = true;
|
|
2424
|
-
|
|
2475
|
+
logger7.info("Block processing aborted", {
|
|
2425
2476
|
subgraph: subgraphName,
|
|
2426
2477
|
currentBlock: currentHeight,
|
|
2427
2478
|
reason: String(opts.signal.reason ?? "unknown")
|
|
@@ -2469,8 +2520,8 @@ async function processBlockRange(def, opts) {
|
|
|
2469
2520
|
preloaded: blockData
|
|
2470
2521
|
});
|
|
2471
2522
|
} catch (err) {
|
|
2472
|
-
const errorMsg =
|
|
2473
|
-
|
|
2523
|
+
const errorMsg = getErrorMessage3(err);
|
|
2524
|
+
logger7.error("Block processing failed persistently", {
|
|
2474
2525
|
subgraph: subgraphName,
|
|
2475
2526
|
blockHeight: height,
|
|
2476
2527
|
error: errorMsg
|
|
@@ -2516,7 +2567,7 @@ async function processBlockRange(def, opts) {
|
|
|
2516
2567
|
lastProgressFlushAt = now;
|
|
2517
2568
|
}
|
|
2518
2569
|
if (blocksProcessed % LOG_INTERVAL === 0) {
|
|
2519
|
-
|
|
2570
|
+
logger7.info(`${status === "reindexing" ? "Reindex" : "Backfill"} progress`, {
|
|
2520
2571
|
subgraph: subgraphName,
|
|
2521
2572
|
processed: blocksProcessed,
|
|
2522
2573
|
total: totalBlocks,
|
|
@@ -2536,7 +2587,7 @@ async function processBlockRange(def, opts) {
|
|
|
2536
2587
|
if (batchFailedBlocks.length > 0 && opts.subgraphId) {
|
|
2537
2588
|
const gaps = coalesceFailedBlocks(batchFailedBlocks);
|
|
2538
2589
|
await recordGapBatch(targetDb, opts.subgraphId, subgraphName, gaps).catch((err) => {
|
|
2539
|
-
|
|
2590
|
+
logger7.warn("Failed to record subgraph gaps", {
|
|
2540
2591
|
subgraph: subgraphName,
|
|
2541
2592
|
error: err instanceof Error ? err.message : String(err)
|
|
2542
2593
|
});
|
|
@@ -2553,7 +2604,7 @@ async function processBlockRange(def, opts) {
|
|
|
2553
2604
|
} else {
|
|
2554
2605
|
await updateSubgraphStatus2(targetDb, subgraphName, status, jumpTo - 1);
|
|
2555
2606
|
}
|
|
2556
|
-
|
|
2607
|
+
logger7.info("Sparse skip", {
|
|
2557
2608
|
subgraph: subgraphName,
|
|
2558
2609
|
from: batchEnd + 1,
|
|
2559
2610
|
to: jumpTo - 1,
|
|
@@ -2593,11 +2644,11 @@ async function reindexSubgraph(def, opts) {
|
|
|
2593
2644
|
const subgraphName = def.name;
|
|
2594
2645
|
const schemaName = opts?.schemaName ?? pgSchemaName(subgraphName);
|
|
2595
2646
|
await updateSubgraphStatus2(targetDb, subgraphName, "reindexing");
|
|
2596
|
-
|
|
2647
|
+
logger7.info("Reindex starting", { subgraph: subgraphName });
|
|
2597
2648
|
try {
|
|
2598
2649
|
const { fromBlock, toBlock } = await resolveBlockRange(source, def, opts);
|
|
2599
2650
|
if (fromBlock > toBlock) {
|
|
2600
|
-
|
|
2651
|
+
logger7.info("No blocks to reindex", {
|
|
2601
2652
|
subgraph: subgraphName,
|
|
2602
2653
|
fromBlock,
|
|
2603
2654
|
toBlock
|
|
@@ -2611,7 +2662,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
2611
2662
|
await client.unsafe(stmt);
|
|
2612
2663
|
}
|
|
2613
2664
|
await updateSubgraphStatus2(targetDb, subgraphName, "reindexing", Math.max(0, fromBlock - 1));
|
|
2614
|
-
|
|
2665
|
+
logger7.info("Schema recreated for reindex", {
|
|
2615
2666
|
subgraph: subgraphName,
|
|
2616
2667
|
cursorResetTo: Math.max(0, fromBlock - 1)
|
|
2617
2668
|
});
|
|
@@ -2625,7 +2676,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
2625
2676
|
last_error_at: null,
|
|
2626
2677
|
updated_at: new Date
|
|
2627
2678
|
}).where("name", "=", subgraphName).execute();
|
|
2628
|
-
|
|
2679
|
+
logger7.info("Reindexing blocks", {
|
|
2629
2680
|
subgraph: subgraphName,
|
|
2630
2681
|
fromBlock,
|
|
2631
2682
|
toBlock,
|
|
@@ -2647,9 +2698,9 @@ async function reindexSubgraph(def, opts) {
|
|
|
2647
2698
|
if (reason === "user-cancelled") {
|
|
2648
2699
|
await updateSubgraphStatus2(targetDb, subgraphName, "active");
|
|
2649
2700
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
2650
|
-
|
|
2701
|
+
logger7.info("Reindex cancelled by user", { subgraph: subgraphName });
|
|
2651
2702
|
} else {
|
|
2652
|
-
|
|
2703
|
+
logger7.info("Reindex interrupted by shutdown, will resume", {
|
|
2653
2704
|
subgraph: subgraphName
|
|
2654
2705
|
});
|
|
2655
2706
|
}
|
|
@@ -2657,17 +2708,22 @@ async function reindexSubgraph(def, opts) {
|
|
|
2657
2708
|
}
|
|
2658
2709
|
await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
|
|
2659
2710
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
2660
|
-
|
|
2711
|
+
logger7.info("Reindex complete", {
|
|
2661
2712
|
subgraph: subgraphName,
|
|
2662
2713
|
blocks: result.blocksProcessed,
|
|
2663
2714
|
events: result.totalEventsProcessed,
|
|
2664
2715
|
errors: result.totalErrors
|
|
2665
2716
|
});
|
|
2717
|
+
notifyReindexComplete(targetDb, subgraphName, {
|
|
2718
|
+
blocks: result.blocksProcessed,
|
|
2719
|
+
events: result.totalEventsProcessed,
|
|
2720
|
+
errors: result.totalErrors
|
|
2721
|
+
});
|
|
2666
2722
|
return { processed: result.blocksProcessed };
|
|
2667
2723
|
} catch (err) {
|
|
2668
|
-
|
|
2724
|
+
logger7.error("Reindex failed", {
|
|
2669
2725
|
subgraph: subgraphName,
|
|
2670
|
-
error:
|
|
2726
|
+
error: getErrorMessage3(err)
|
|
2671
2727
|
});
|
|
2672
2728
|
await updateSubgraphStatus2(targetDb, subgraphName, "error");
|
|
2673
2729
|
throw err;
|
|
@@ -2687,7 +2743,7 @@ async function resumeReindex(def, opts) {
|
|
|
2687
2743
|
const fromBlock = resolveReindexResumeBlock(row);
|
|
2688
2744
|
const toBlock = Number(row.reindex_to_block);
|
|
2689
2745
|
if (fromBlock == null) {
|
|
2690
|
-
|
|
2746
|
+
logger7.info("No reindex metadata, starting fresh reindex", {
|
|
2691
2747
|
subgraph: subgraphName
|
|
2692
2748
|
});
|
|
2693
2749
|
return reindexSubgraph(def, {
|
|
@@ -2696,12 +2752,12 @@ async function resumeReindex(def, opts) {
|
|
|
2696
2752
|
});
|
|
2697
2753
|
}
|
|
2698
2754
|
if (fromBlock > toBlock) {
|
|
2699
|
-
|
|
2755
|
+
logger7.info("Resume: no remaining blocks", { subgraph: subgraphName });
|
|
2700
2756
|
await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
|
|
2701
2757
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
2702
2758
|
return { processed: 0 };
|
|
2703
2759
|
}
|
|
2704
|
-
|
|
2760
|
+
logger7.info("Resuming reindex", {
|
|
2705
2761
|
subgraph: subgraphName,
|
|
2706
2762
|
fromBlock,
|
|
2707
2763
|
toBlock,
|
|
@@ -2723,9 +2779,9 @@ async function resumeReindex(def, opts) {
|
|
|
2723
2779
|
if (reason === "user-cancelled") {
|
|
2724
2780
|
await updateSubgraphStatus2(targetDb, subgraphName, "active");
|
|
2725
2781
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
2726
|
-
|
|
2782
|
+
logger7.info("Resume cancelled by user", { subgraph: subgraphName });
|
|
2727
2783
|
} else {
|
|
2728
|
-
|
|
2784
|
+
logger7.info("Resume interrupted by shutdown, will resume again", {
|
|
2729
2785
|
subgraph: subgraphName
|
|
2730
2786
|
});
|
|
2731
2787
|
}
|
|
@@ -2733,15 +2789,15 @@ async function resumeReindex(def, opts) {
|
|
|
2733
2789
|
}
|
|
2734
2790
|
await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
|
|
2735
2791
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
2736
|
-
|
|
2792
|
+
logger7.info("Resumed reindex complete", {
|
|
2737
2793
|
subgraph: subgraphName,
|
|
2738
2794
|
blocks: result.blocksProcessed
|
|
2739
2795
|
});
|
|
2740
2796
|
return { processed: result.blocksProcessed };
|
|
2741
2797
|
} catch (err) {
|
|
2742
|
-
|
|
2798
|
+
logger7.error("Resumed reindex failed", {
|
|
2743
2799
|
subgraph: subgraphName,
|
|
2744
|
-
error:
|
|
2800
|
+
error: getErrorMessage3(err)
|
|
2745
2801
|
});
|
|
2746
2802
|
await updateSubgraphStatus2(targetDb, subgraphName, "error");
|
|
2747
2803
|
throw err;
|
|
@@ -2750,7 +2806,7 @@ async function resumeReindex(def, opts) {
|
|
|
2750
2806
|
async function backfillSubgraph(def, opts) {
|
|
2751
2807
|
const targetDb = getTargetDb2();
|
|
2752
2808
|
const subgraphName = def.name;
|
|
2753
|
-
|
|
2809
|
+
logger7.info("Backfill starting", {
|
|
2754
2810
|
subgraph: subgraphName,
|
|
2755
2811
|
from: opts.fromBlock,
|
|
2756
2812
|
to: opts.toBlock
|
|
@@ -2768,17 +2824,17 @@ async function backfillSubgraph(def, opts) {
|
|
|
2768
2824
|
signal: opts.signal
|
|
2769
2825
|
});
|
|
2770
2826
|
if (result.aborted) {
|
|
2771
|
-
|
|
2827
|
+
logger7.info("Backfill aborted", { subgraph: subgraphName });
|
|
2772
2828
|
return { processed: result.blocksProcessed };
|
|
2773
2829
|
}
|
|
2774
2830
|
const resolved = await resolveGaps(targetDb, subgraphName, opts.fromBlock, opts.toBlock).catch(() => 0);
|
|
2775
2831
|
if (resolved > 0) {
|
|
2776
|
-
|
|
2832
|
+
logger7.info("Resolved subgraph gaps via backfill", {
|
|
2777
2833
|
subgraph: subgraphName,
|
|
2778
2834
|
resolved
|
|
2779
2835
|
});
|
|
2780
2836
|
}
|
|
2781
|
-
|
|
2837
|
+
logger7.info("Backfill complete", {
|
|
2782
2838
|
subgraph: subgraphName,
|
|
2783
2839
|
blocks: result.blocksProcessed,
|
|
2784
2840
|
events: result.totalEventsProcessed,
|
|
@@ -2786,9 +2842,9 @@ async function backfillSubgraph(def, opts) {
|
|
|
2786
2842
|
});
|
|
2787
2843
|
return { processed: result.blocksProcessed };
|
|
2788
2844
|
} catch (err) {
|
|
2789
|
-
|
|
2845
|
+
logger7.error("Backfill failed", {
|
|
2790
2846
|
subgraph: subgraphName,
|
|
2791
|
-
error:
|
|
2847
|
+
error: getErrorMessage3(err)
|
|
2792
2848
|
});
|
|
2793
2849
|
throw err;
|
|
2794
2850
|
}
|
|
@@ -2802,5 +2858,5 @@ export {
|
|
|
2802
2858
|
backfillSubgraph
|
|
2803
2859
|
};
|
|
2804
2860
|
|
|
2805
|
-
//# debugId=
|
|
2861
|
+
//# debugId=316D16E7196F1A6A64756E2164756E21
|
|
2806
2862
|
//# sourceMappingURL=reindex.js.map
|