@secondlayer/subgraphs 3.24.1 → 3.24.2
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 +361 -39
- package/dist/src/index.js.map +7 -4
- package/dist/src/runtime/block-processor.d.ts +8 -1
- package/dist/src/runtime/block-processor.js +331 -9
- package/dist/src/runtime/block-processor.js.map +7 -4
- package/dist/src/runtime/catchup.js +340 -18
- package/dist/src/runtime/catchup.js.map +7 -4
- package/dist/src/runtime/processor.js +401 -79
- package/dist/src/runtime/processor.js.map +7 -4
- package/dist/src/runtime/reindex.js +361 -39
- package/dist/src/runtime/reindex.js.map +7 -4
- package/dist/src/runtime/reorg.js +347 -25
- package/dist/src/runtime/reorg.js.map +7 -4
- package/dist/src/service.js +404 -82
- package/dist/src/service.js.map +7 -4
- package/package.json +1 -1
|
@@ -1639,7 +1639,7 @@ import {
|
|
|
1639
1639
|
rewindLiveProgress,
|
|
1640
1640
|
updateSubgraphStatus
|
|
1641
1641
|
} from "@secondlayer/shared/db/queries/subgraphs";
|
|
1642
|
-
import { logger as
|
|
1642
|
+
import { logger as logger7 } from "@secondlayer/shared/logger";
|
|
1643
1643
|
import { sql as sql3 } from "kysely";
|
|
1644
1644
|
|
|
1645
1645
|
// src/runtime/block-source.ts
|
|
@@ -2080,6 +2080,315 @@ async function emitSubscriptionOutbox(tx, subgraphName, manifest, matcher, block
|
|
|
2080
2080
|
return rows.length;
|
|
2081
2081
|
}
|
|
2082
2082
|
|
|
2083
|
+
// src/runtime/sandbox/flag.ts
|
|
2084
|
+
function sandboxWorkersGloballyEnabled() {
|
|
2085
|
+
return process.env.SUBGRAPH_SANDBOX_WORKERS === "1";
|
|
2086
|
+
}
|
|
2087
|
+
function sandboxEnabled(subgraph) {
|
|
2088
|
+
return sandboxWorkersGloballyEnabled() && subgraph.sandbox_workers === true;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
// src/runtime/sandbox/host.ts
|
|
2092
|
+
import { tmpdir } from "node:os";
|
|
2093
|
+
import { fileURLToPath } from "node:url";
|
|
2094
|
+
import { logger as logger6 } from "@secondlayer/shared/logger";
|
|
2095
|
+
|
|
2096
|
+
// src/runtime/sandbox/bundle.ts
|
|
2097
|
+
import esbuild from "esbuild";
|
|
2098
|
+
var ALLOWED_BARE_SPECIFIERS = new Set;
|
|
2099
|
+
var SUBGRAPHS_PACKAGE_SPECIFIER = "@secondlayer/subgraphs";
|
|
2100
|
+
var SUBGRAPHS_STUB_SOURCE = `export function defineSubgraph(def) { return def; }
|
|
2101
|
+
`;
|
|
2102
|
+
function resolverLockdownPlugin() {
|
|
2103
|
+
return {
|
|
2104
|
+
name: "f071-sandbox-resolver-lockdown",
|
|
2105
|
+
setup(build) {
|
|
2106
|
+
build.onResolve({ filter: /^@secondlayer\/subgraphs$/ }, (args) => ({
|
|
2107
|
+
path: args.path,
|
|
2108
|
+
namespace: "f071-sandbox-subgraphs-stub"
|
|
2109
|
+
}));
|
|
2110
|
+
build.onLoad({ filter: /.*/, namespace: "f071-sandbox-subgraphs-stub" }, () => ({ contents: SUBGRAPHS_STUB_SOURCE, loader: "js" }));
|
|
2111
|
+
build.onResolve({ filter: /^(node:|bun:)/ }, (args) => ({
|
|
2112
|
+
path: args.path,
|
|
2113
|
+
namespace: "f071-sandbox-blocked"
|
|
2114
|
+
}));
|
|
2115
|
+
build.onResolve({ filter: /^[^./]/ }, (args) => {
|
|
2116
|
+
if (args.path === SUBGRAPHS_PACKAGE_SPECIFIER)
|
|
2117
|
+
return;
|
|
2118
|
+
if (ALLOWED_BARE_SPECIFIERS.has(args.path))
|
|
2119
|
+
return;
|
|
2120
|
+
return { path: args.path, namespace: "f071-sandbox-blocked" };
|
|
2121
|
+
});
|
|
2122
|
+
build.onLoad({ filter: /.*/, namespace: "f071-sandbox-blocked" }, (args) => ({
|
|
2123
|
+
contents: `throw new Error(${JSON.stringify(`subgraph sandbox: import of "${args.path}" is blocked in sandboxed handler code — handlers must use the injected \`ctx\` for all I/O`)});`,
|
|
2124
|
+
loader: "js"
|
|
2125
|
+
}));
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
}
|
|
2129
|
+
async function bundleHandlerCode(handlerCode) {
|
|
2130
|
+
const result = await esbuild.build({
|
|
2131
|
+
stdin: {
|
|
2132
|
+
contents: handlerCode,
|
|
2133
|
+
loader: "ts",
|
|
2134
|
+
resolveDir: process.cwd()
|
|
2135
|
+
},
|
|
2136
|
+
bundle: true,
|
|
2137
|
+
platform: "neutral",
|
|
2138
|
+
format: "esm",
|
|
2139
|
+
write: false,
|
|
2140
|
+
logLevel: "silent",
|
|
2141
|
+
plugins: [resolverLockdownPlugin()]
|
|
2142
|
+
});
|
|
2143
|
+
const out = result.outputFiles?.[0];
|
|
2144
|
+
if (!out)
|
|
2145
|
+
throw new Error("esbuild produced no output for handler_code bundle");
|
|
2146
|
+
return new TextDecoder().decode(out.contents);
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
// src/runtime/sandbox/host.ts
|
|
2150
|
+
var BLOCK_TIMEOUT_MS = Number.parseInt(process.env.SUBGRAPH_SANDBOX_BLOCK_TIMEOUT_MS ?? "60000");
|
|
2151
|
+
var SUBPROCESS_ENTRY_PATH = fileURLToPath(new URL("./subprocess-entry.ts", import.meta.url));
|
|
2152
|
+
function spawnSandboxProcess() {
|
|
2153
|
+
let onMessage = null;
|
|
2154
|
+
const proc = Bun.spawn({
|
|
2155
|
+
cmd: [process.execPath, "--no-env-file", SUBPROCESS_ENTRY_PATH],
|
|
2156
|
+
env: { PATH: process.env.PATH ?? "" },
|
|
2157
|
+
cwd: tmpdir(),
|
|
2158
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
2159
|
+
serialization: "advanced",
|
|
2160
|
+
ipc(message) {
|
|
2161
|
+
onMessage?.(message);
|
|
2162
|
+
}
|
|
2163
|
+
});
|
|
2164
|
+
(async () => {
|
|
2165
|
+
const reader = proc.stderr.getReader();
|
|
2166
|
+
const decoder = new TextDecoder;
|
|
2167
|
+
try {
|
|
2168
|
+
while (true) {
|
|
2169
|
+
const { done, value } = await reader.read();
|
|
2170
|
+
if (done)
|
|
2171
|
+
break;
|
|
2172
|
+
const text = decoder.decode(value, { stream: true });
|
|
2173
|
+
if (text.trim()) {
|
|
2174
|
+
logger6.warn("Sandbox subprocess stderr", { stderr: text.trim() });
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
} catch {}
|
|
2178
|
+
})();
|
|
2179
|
+
return {
|
|
2180
|
+
send: (msg) => proc.send(msg),
|
|
2181
|
+
kill: () => proc.kill(),
|
|
2182
|
+
exited: proc.exited,
|
|
2183
|
+
setOnMessage: (handler) => {
|
|
2184
|
+
onMessage = handler;
|
|
2185
|
+
}
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
var pool = new Map;
|
|
2189
|
+
|
|
2190
|
+
class SandboxWorkerCrash extends Error {
|
|
2191
|
+
constructor(subgraphName, cause) {
|
|
2192
|
+
super(`sandbox subprocess for "${subgraphName}" failed: ${cause}`);
|
|
2193
|
+
this.name = "SandboxWorkerCrash";
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
async function initSandboxProcess(proc, subgraphName, version, handlerCode) {
|
|
2197
|
+
const bundledCode = await bundleHandlerCode(handlerCode);
|
|
2198
|
+
let settled = false;
|
|
2199
|
+
const ready = new Promise((resolve, reject) => {
|
|
2200
|
+
proc.setOnMessage((msg) => {
|
|
2201
|
+
if (msg.type === "ready" && msg.version === version) {
|
|
2202
|
+
settled = true;
|
|
2203
|
+
proc.setOnMessage(null);
|
|
2204
|
+
resolve();
|
|
2205
|
+
} else if (msg.type === "error") {
|
|
2206
|
+
settled = true;
|
|
2207
|
+
proc.setOnMessage(null);
|
|
2208
|
+
reject(new SandboxWorkerCrash(subgraphName, msg.message));
|
|
2209
|
+
}
|
|
2210
|
+
});
|
|
2211
|
+
const init = { type: "init", bundledCode, version };
|
|
2212
|
+
proc.send(init);
|
|
2213
|
+
});
|
|
2214
|
+
const crashed = proc.exited.then((code) => {
|
|
2215
|
+
if (settled)
|
|
2216
|
+
return;
|
|
2217
|
+
throw new SandboxWorkerCrash(subgraphName, `subprocess exited (code ${code}) during init`);
|
|
2218
|
+
});
|
|
2219
|
+
await Promise.race([ready, crashed]);
|
|
2220
|
+
}
|
|
2221
|
+
async function ensureSandboxProcess(subgraphName, version, handlerCode) {
|
|
2222
|
+
if (handlerCode == null) {
|
|
2223
|
+
throw new SandboxWorkerCrash(subgraphName, "subgraph has no handler_code; cannot bundle for the sandbox path");
|
|
2224
|
+
}
|
|
2225
|
+
const existing = pool.get(subgraphName);
|
|
2226
|
+
if (existing && existing.version === version)
|
|
2227
|
+
return existing;
|
|
2228
|
+
if (existing) {
|
|
2229
|
+
try {
|
|
2230
|
+
await initSandboxProcess(existing.proc, subgraphName, version, handlerCode);
|
|
2231
|
+
existing.version = version;
|
|
2232
|
+
logger6.info("Sandbox subprocess handler reloaded", {
|
|
2233
|
+
subgraph: subgraphName,
|
|
2234
|
+
version
|
|
2235
|
+
});
|
|
2236
|
+
return existing;
|
|
2237
|
+
} catch (err) {
|
|
2238
|
+
existing.proc.kill();
|
|
2239
|
+
pool.delete(subgraphName);
|
|
2240
|
+
logger6.warn("Sandbox subprocess re-init failed; respawning", {
|
|
2241
|
+
subgraph: subgraphName,
|
|
2242
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2243
|
+
});
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
const proc = spawnSandboxProcess();
|
|
2247
|
+
try {
|
|
2248
|
+
await initSandboxProcess(proc, subgraphName, version, handlerCode);
|
|
2249
|
+
} catch (err) {
|
|
2250
|
+
proc.kill();
|
|
2251
|
+
throw err;
|
|
2252
|
+
}
|
|
2253
|
+
const entry = { proc, version, chain: Promise.resolve() };
|
|
2254
|
+
pool.set(subgraphName, entry);
|
|
2255
|
+
return entry;
|
|
2256
|
+
}
|
|
2257
|
+
function evictSandboxWorker(subgraphName) {
|
|
2258
|
+
const entry = pool.get(subgraphName);
|
|
2259
|
+
if (!entry)
|
|
2260
|
+
return;
|
|
2261
|
+
entry.proc.kill();
|
|
2262
|
+
pool.delete(subgraphName);
|
|
2263
|
+
}
|
|
2264
|
+
async function runHandlersSandboxed(params) {
|
|
2265
|
+
const { subgraphName, version, handlerCode, hostCtx, block, matched } = params;
|
|
2266
|
+
const entry = await ensureSandboxProcess(subgraphName, version, handlerCode);
|
|
2267
|
+
const run = entry.chain.then(() => runBlockThroughProcess(entry, subgraphName, hostCtx, block, matched));
|
|
2268
|
+
entry.chain = run.catch(() => {
|
|
2269
|
+
return;
|
|
2270
|
+
});
|
|
2271
|
+
return run;
|
|
2272
|
+
}
|
|
2273
|
+
async function runBlockThroughProcess(entry, subgraphName, hostCtx, block, matched) {
|
|
2274
|
+
const { proc } = entry;
|
|
2275
|
+
let timeoutHandle;
|
|
2276
|
+
let settled = false;
|
|
2277
|
+
try {
|
|
2278
|
+
const done = new Promise((resolve, reject) => {
|
|
2279
|
+
proc.setOnMessage((msg) => {
|
|
2280
|
+
if (msg.type === "readRequest") {
|
|
2281
|
+
answerRead(hostCtx, msg).then((reply) => {
|
|
2282
|
+
proc.send({ type: "readResponse", id: msg.id, reply });
|
|
2283
|
+
}).catch((err) => {
|
|
2284
|
+
settled = true;
|
|
2285
|
+
reject(new SandboxWorkerCrash(subgraphName, `host read failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
2286
|
+
});
|
|
2287
|
+
return;
|
|
2288
|
+
}
|
|
2289
|
+
if (msg.type === "blockDone") {
|
|
2290
|
+
settled = true;
|
|
2291
|
+
resolve({
|
|
2292
|
+
ops: msg.ops,
|
|
2293
|
+
result: { processed: msg.processed, errors: msg.errors }
|
|
2294
|
+
});
|
|
2295
|
+
return;
|
|
2296
|
+
}
|
|
2297
|
+
if (msg.type === "error") {
|
|
2298
|
+
settled = true;
|
|
2299
|
+
reject(new SandboxWorkerCrash(subgraphName, msg.message));
|
|
2300
|
+
}
|
|
2301
|
+
});
|
|
2302
|
+
proc.send({ type: "runBlock", block, matched });
|
|
2303
|
+
});
|
|
2304
|
+
const crashed = proc.exited.then((code) => {
|
|
2305
|
+
if (settled)
|
|
2306
|
+
return;
|
|
2307
|
+
throw new SandboxWorkerCrash(subgraphName, `subprocess exited unexpectedly (code ${code}) mid-block`);
|
|
2308
|
+
});
|
|
2309
|
+
const deadline = new Promise((_, reject) => {
|
|
2310
|
+
timeoutHandle = setTimeout(() => {
|
|
2311
|
+
settled = true;
|
|
2312
|
+
reject(new SandboxWorkerCrash(subgraphName, `block ${block.height} exceeded ${BLOCK_TIMEOUT_MS}ms deadline`));
|
|
2313
|
+
}, BLOCK_TIMEOUT_MS);
|
|
2314
|
+
});
|
|
2315
|
+
const { ops, result } = await Promise.race([done, crashed, deadline]);
|
|
2316
|
+
for (const op of ops) {
|
|
2317
|
+
hostCtx.setTx(op.tx);
|
|
2318
|
+
replayOp(hostCtx, op);
|
|
2319
|
+
}
|
|
2320
|
+
return result;
|
|
2321
|
+
} catch (err) {
|
|
2322
|
+
evictSandboxWorker(subgraphName);
|
|
2323
|
+
logger6.warn("Sandbox subprocess run failed; subprocess evicted", {
|
|
2324
|
+
subgraph: subgraphName,
|
|
2325
|
+
blockHeight: block.height,
|
|
2326
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2327
|
+
});
|
|
2328
|
+
throw err;
|
|
2329
|
+
} finally {
|
|
2330
|
+
if (timeoutHandle !== undefined)
|
|
2331
|
+
clearTimeout(timeoutHandle);
|
|
2332
|
+
proc.setOnMessage(null);
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
function replayOp(hostCtx, op) {
|
|
2336
|
+
switch (op.method) {
|
|
2337
|
+
case "insert":
|
|
2338
|
+
hostCtx.insert(op.table, op.args[0]);
|
|
2339
|
+
return;
|
|
2340
|
+
case "upsert":
|
|
2341
|
+
hostCtx.upsert(op.table, op.args[0], op.args[1]);
|
|
2342
|
+
return;
|
|
2343
|
+
case "increment":
|
|
2344
|
+
hostCtx.increment(op.table, op.args[0], op.args[1]);
|
|
2345
|
+
return;
|
|
2346
|
+
case "update":
|
|
2347
|
+
hostCtx.update(op.table, op.args[0], op.args[1]);
|
|
2348
|
+
return;
|
|
2349
|
+
case "delete":
|
|
2350
|
+
hostCtx.delete(op.table, op.args[0]);
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
async function answerRead(hostCtx, msg) {
|
|
2355
|
+
const { method, table, where, column } = msg;
|
|
2356
|
+
switch (method) {
|
|
2357
|
+
case "findOne":
|
|
2358
|
+
return { kind: "row", row: await hostCtx.findOne(table, where) };
|
|
2359
|
+
case "findMany":
|
|
2360
|
+
return { kind: "rows", rows: await hostCtx.findMany(table, where) };
|
|
2361
|
+
case "count":
|
|
2362
|
+
return { kind: "count", count: await hostCtx.count(table, where) };
|
|
2363
|
+
case "countDistinct": {
|
|
2364
|
+
if (!column)
|
|
2365
|
+
throw new Error("countDistinct read missing column");
|
|
2366
|
+
return {
|
|
2367
|
+
kind: "count",
|
|
2368
|
+
count: await hostCtx.countDistinct(table, column, where)
|
|
2369
|
+
};
|
|
2370
|
+
}
|
|
2371
|
+
case "sum": {
|
|
2372
|
+
if (!column)
|
|
2373
|
+
throw new Error("sum read missing column");
|
|
2374
|
+
const v = await hostCtx.sum(table, column, where);
|
|
2375
|
+
return { kind: "amount", amount: v.toString() };
|
|
2376
|
+
}
|
|
2377
|
+
case "min": {
|
|
2378
|
+
if (!column)
|
|
2379
|
+
throw new Error("min read missing column");
|
|
2380
|
+
const v = await hostCtx.min(table, column, where);
|
|
2381
|
+
return { kind: "amount", amount: v == null ? null : v.toString() };
|
|
2382
|
+
}
|
|
2383
|
+
case "max": {
|
|
2384
|
+
if (!column)
|
|
2385
|
+
throw new Error("max read missing column");
|
|
2386
|
+
const v = await hostCtx.max(table, column, where);
|
|
2387
|
+
return { kind: "amount", amount: v == null ? null : v.toString() };
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2083
2392
|
// src/runtime/subscription-state.ts
|
|
2084
2393
|
import { listSubscriptions } from "@secondlayer/shared/db/queries/subscriptions";
|
|
2085
2394
|
import { sql as sql2 } from "kysely";
|
|
@@ -2264,13 +2573,17 @@ async function resolveRoute(subgraphName, targetDb) {
|
|
|
2264
2573
|
const route = {
|
|
2265
2574
|
schemaName: row?.schema_name ?? pgSchemaName(subgraphName),
|
|
2266
2575
|
dataDb: row && byo ? resolveSubgraphDb(row) : targetDb,
|
|
2267
|
-
byo
|
|
2576
|
+
byo,
|
|
2577
|
+
sandboxWorkers: row?.sandbox_workers === true,
|
|
2578
|
+
handlerCode: row?.handler_code ?? null,
|
|
2579
|
+
version: row?.version ?? ""
|
|
2268
2580
|
};
|
|
2269
2581
|
routeCache.set(subgraphName, route);
|
|
2270
2582
|
return route;
|
|
2271
2583
|
}
|
|
2272
2584
|
function invalidateSubgraphRoute(subgraphName) {
|
|
2273
2585
|
routeCache.delete(subgraphName);
|
|
2586
|
+
evictSandboxWorker(subgraphName);
|
|
2274
2587
|
}
|
|
2275
2588
|
async function resolveFactoryContracts(subgraph, blockHeight, schemaName, db, txs, evts) {
|
|
2276
2589
|
const factories = new Map;
|
|
@@ -2376,7 +2689,7 @@ async function processBlockWithRetry(subgraph, subgraphName, blockHeight, opts,
|
|
|
2376
2689
|
const delay = retryDelaysMs[attempt];
|
|
2377
2690
|
if (delay === undefined)
|
|
2378
2691
|
break;
|
|
2379
|
-
|
|
2692
|
+
logger7.warn("Block processing failed, retrying", {
|
|
2380
2693
|
subgraph: subgraphName,
|
|
2381
2694
|
blockHeight,
|
|
2382
2695
|
attempt: attempt + 1,
|
|
@@ -2408,7 +2721,7 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
2408
2721
|
} else {
|
|
2409
2722
|
const data = (await resolveBlockSource(subgraph).loadBlockRange(blockHeight, blockHeight)).get(blockHeight);
|
|
2410
2723
|
if (!data) {
|
|
2411
|
-
|
|
2724
|
+
logger7.debug("Block not found or non-canonical for subgraph processing", {
|
|
2412
2725
|
subgraph: subgraphName,
|
|
2413
2726
|
blockHeight
|
|
2414
2727
|
});
|
|
@@ -2544,7 +2857,16 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
2544
2857
|
}
|
|
2545
2858
|
const ctx = new SubgraphContext(tx, schemaName, subgraph.schema, blockMeta, initialTx, false, journalEnabled(opts));
|
|
2546
2859
|
const handlerStart = performance.now();
|
|
2547
|
-
const runResult =
|
|
2860
|
+
const runResult = sandboxEnabled({
|
|
2861
|
+
sandbox_workers: route.sandboxWorkers
|
|
2862
|
+
}) ? await runHandlersSandboxed({
|
|
2863
|
+
subgraphName,
|
|
2864
|
+
version: route.version,
|
|
2865
|
+
handlerCode: route.handlerCode,
|
|
2866
|
+
hostCtx: ctx,
|
|
2867
|
+
block: blockMeta,
|
|
2868
|
+
matched
|
|
2869
|
+
}) : await runHandlers(subgraph, matched, ctx);
|
|
2548
2870
|
handlerMs = performance.now() - handlerStart;
|
|
2549
2871
|
result.processed = runResult.processed;
|
|
2550
2872
|
result.errors = runResult.errors;
|
|
@@ -2570,7 +2892,7 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
2570
2892
|
});
|
|
2571
2893
|
} catch (err) {
|
|
2572
2894
|
if (err instanceof CursorRaceLostError || err instanceof LiveCursorRaceLostError) {
|
|
2573
|
-
|
|
2895
|
+
logger7.warn("cursor race lost — block already covered", {
|
|
2574
2896
|
subgraph: subgraphName,
|
|
2575
2897
|
blockHeight,
|
|
2576
2898
|
error: err.message
|
|
@@ -2596,7 +2918,7 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
2596
2918
|
const { rows } = await sql3.raw(`SELECT n_live_tup AS count FROM pg_stat_user_tables WHERE schemaname = '${schemaName}' AND relname = '${table}'`).execute(route.dataDb);
|
|
2597
2919
|
const count = Number(rows[0]?.count ?? 0);
|
|
2598
2920
|
if (count >= 1e7) {
|
|
2599
|
-
|
|
2921
|
+
logger7.warn("Subgraph table exceeds 10M rows (estimate)", {
|
|
2600
2922
|
subgraph: subgraphName,
|
|
2601
2923
|
table,
|
|
2602
2924
|
count
|
|
@@ -2604,7 +2926,7 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
2604
2926
|
}
|
|
2605
2927
|
}
|
|
2606
2928
|
} catch (err) {
|
|
2607
|
-
|
|
2929
|
+
logger7.debug("Row count sample failed", {
|
|
2608
2930
|
subgraph: subgraphName,
|
|
2609
2931
|
error: err instanceof Error ? err.message : String(err)
|
|
2610
2932
|
});
|
|
@@ -2682,7 +3004,7 @@ class StatsAccumulator {
|
|
|
2682
3004
|
// src/runtime/catchup.ts
|
|
2683
3005
|
import { getTargetDb as getTargetDb2 } from "@secondlayer/shared/db";
|
|
2684
3006
|
import { getSubgraph } from "@secondlayer/shared/db/queries/subgraphs";
|
|
2685
|
-
import { logger as
|
|
3007
|
+
import { logger as logger8 } from "@secondlayer/shared/logger";
|
|
2686
3008
|
|
|
2687
3009
|
// src/runtime/catchup-leader.ts
|
|
2688
3010
|
import {
|
|
@@ -2816,7 +3138,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
2816
3138
|
const subgraphStart = Number(subgraphRow.start_block) || 1;
|
|
2817
3139
|
const startBlock = Math.max(lastProcessedBlock + 1, subgraphStart);
|
|
2818
3140
|
const totalBlocks = chainTip - lastProcessedBlock;
|
|
2819
|
-
|
|
3141
|
+
logger8.info("Subgraph catch-up starting", {
|
|
2820
3142
|
subgraph: subgraphName,
|
|
2821
3143
|
from: startBlock,
|
|
2822
3144
|
to: chainTip,
|
|
@@ -2832,7 +3154,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
2832
3154
|
let nextBatchPromise = batchConfig.prefetch ? source.loadBlockRange(currentHeight, prefetchedBatchEnd) : undefined;
|
|
2833
3155
|
while (currentHeight <= chainTip) {
|
|
2834
3156
|
if (!isCatchUpLeader()) {
|
|
2835
|
-
|
|
3157
|
+
logger8.info("Lost catch-up leadership, stopping catch-up", {
|
|
2836
3158
|
subgraph: subgraphName,
|
|
2837
3159
|
processed
|
|
2838
3160
|
});
|
|
@@ -2840,7 +3162,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
2840
3162
|
}
|
|
2841
3163
|
const currentRow = await getSubgraph(targetDb, subgraphName);
|
|
2842
3164
|
if (!currentRow || currentRow.status !== "active") {
|
|
2843
|
-
|
|
3165
|
+
logger8.info("Subgraph status changed, stopping catch-up", {
|
|
2844
3166
|
subgraph: subgraphName,
|
|
2845
3167
|
status: currentRow?.status ?? "deleted"
|
|
2846
3168
|
});
|
|
@@ -2869,7 +3191,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
2869
3191
|
blockData = (await source.loadBlockRange(height, height)).get(height);
|
|
2870
3192
|
}
|
|
2871
3193
|
if (!blockData) {
|
|
2872
|
-
|
|
3194
|
+
logger8.warn("Block missing during catch-up, deferring to next tick", {
|
|
2873
3195
|
subgraph: subgraphName,
|
|
2874
3196
|
blockHeight: height
|
|
2875
3197
|
});
|
|
@@ -2889,12 +3211,12 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
2889
3211
|
});
|
|
2890
3212
|
} catch (err) {
|
|
2891
3213
|
if (err instanceof ReorgEpochChangedError) {
|
|
2892
|
-
|
|
3214
|
+
logger8.info("Reorg detected mid catch-up, aborting walk without writing further progress", { subgraph: subgraphName, blockHeight: height });
|
|
2893
3215
|
stopCatchup = true;
|
|
2894
3216
|
break;
|
|
2895
3217
|
}
|
|
2896
3218
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
2897
|
-
|
|
3219
|
+
logger8.error("Block processing failed persistently during catch-up", {
|
|
2898
3220
|
subgraph: subgraphName,
|
|
2899
3221
|
blockHeight: height,
|
|
2900
3222
|
error: errorMsg
|
|
@@ -2913,7 +3235,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
2913
3235
|
}
|
|
2914
3236
|
}
|
|
2915
3237
|
if (processed % LOG_INTERVAL === 0) {
|
|
2916
|
-
|
|
3238
|
+
logger8.info("Subgraph catch-up progress", {
|
|
2917
3239
|
subgraph: subgraphName,
|
|
2918
3240
|
processed,
|
|
2919
3241
|
total: totalBlocks,
|
|
@@ -2929,7 +3251,7 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
2929
3251
|
currentHeight = batchEnd + 1;
|
|
2930
3252
|
}
|
|
2931
3253
|
await stats.flush(targetDb);
|
|
2932
|
-
|
|
3254
|
+
logger8.info("Subgraph catch-up complete", {
|
|
2933
3255
|
subgraph: subgraphName,
|
|
2934
3256
|
processed
|
|
2935
3257
|
});
|
|
@@ -2945,5 +3267,5 @@ export {
|
|
|
2945
3267
|
bumpReorgEpoch
|
|
2946
3268
|
};
|
|
2947
3269
|
|
|
2948
|
-
//# debugId=
|
|
3270
|
+
//# debugId=E2B1B807C9857E3764756E2164756E21
|
|
2949
3271
|
//# sourceMappingURL=catchup.js.map
|