@secondlayer/subgraphs 3.6.0 → 3.7.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 +16 -11
- package/dist/src/index.js.map +6 -6
- package/dist/src/runtime/block-processor.js +16 -11
- package/dist/src/runtime/block-processor.js.map +6 -6
- package/dist/src/runtime/catchup.js +16 -11
- package/dist/src/runtime/catchup.js.map +6 -6
- package/dist/src/runtime/processor.js +340 -65
- package/dist/src/runtime/processor.js.map +12 -9
- package/dist/src/runtime/reindex.js +16 -11
- package/dist/src/runtime/reindex.js.map +6 -6
- package/dist/src/runtime/reorg.js +16 -11
- package/dist/src/runtime/reorg.js.map +6 -6
- package/dist/src/runtime/replay.js +12 -7
- package/dist/src/runtime/replay.js.map +3 -3
- package/dist/src/runtime/runner.js +4 -2
- package/dist/src/runtime/runner.js.map +3 -3
- package/dist/src/service.js +343 -68
- package/dist/src/service.js.map +12 -9
- package/package.json +2 -2
package/dist/src/service.js
CHANGED
|
@@ -578,9 +578,11 @@ function buildEventPayload(filter, tx, event) {
|
|
|
578
578
|
};
|
|
579
579
|
}
|
|
580
580
|
case "contract_call": {
|
|
581
|
+
const ccRawHex = event.data?.raw_value;
|
|
582
|
+
const normalized = typeof ccRawHex === "string" && ccRawHex.startsWith("0x") ? { ...decoded, value: decodeClarityValue(ccRawHex) } : decoded;
|
|
581
583
|
const input = buildContractCallInput(filter, tx);
|
|
582
584
|
return {
|
|
583
|
-
...
|
|
585
|
+
...normalized,
|
|
584
586
|
type: "contract_call",
|
|
585
587
|
_eventType: event.type,
|
|
586
588
|
contractId: tx.contract_id ?? "",
|
|
@@ -1089,7 +1091,7 @@ function reconstructEvent(e) {
|
|
|
1089
1091
|
sender: e.sender,
|
|
1090
1092
|
recipient: e.recipient,
|
|
1091
1093
|
amount: e.amount,
|
|
1092
|
-
..."
|
|
1094
|
+
...e.event_type === "stx_transfer" ? { memo: e.memo ?? "" } : {}
|
|
1093
1095
|
}
|
|
1094
1096
|
};
|
|
1095
1097
|
case "stx_lock":
|
|
@@ -1108,7 +1110,6 @@ function reconstructEvent(e) {
|
|
|
1108
1110
|
type: "contract_event",
|
|
1109
1111
|
data: {
|
|
1110
1112
|
topic: e.payload.topic,
|
|
1111
|
-
contract_id: e.contract_id,
|
|
1112
1113
|
contract_identifier: e.contract_id,
|
|
1113
1114
|
value: e.payload.value,
|
|
1114
1115
|
raw_value: e.payload.raw_value
|
|
@@ -1148,19 +1149,21 @@ function sourceFilters(subgraph) {
|
|
|
1148
1149
|
const sources = subgraph.sources;
|
|
1149
1150
|
return Array.isArray(sources) ? sources : Object.values(sources);
|
|
1150
1151
|
}
|
|
1151
|
-
function
|
|
1152
|
-
|
|
1153
|
-
if (filters.some((f) => TX_SOURCE_TYPES.has(f.type))) {
|
|
1152
|
+
function indexEventTypesForFilterTypes(filterTypes) {
|
|
1153
|
+
if (filterTypes.some((t) => TX_SOURCE_TYPES.has(t))) {
|
|
1154
1154
|
return ALL_INDEX_EVENT_TYPES;
|
|
1155
1155
|
}
|
|
1156
1156
|
const types = new Set;
|
|
1157
|
-
for (const
|
|
1158
|
-
const
|
|
1159
|
-
if (
|
|
1160
|
-
types.add(
|
|
1157
|
+
for (const t of filterTypes) {
|
|
1158
|
+
const indexType = EVENT_FILTER_TO_INDEX_TYPE[t];
|
|
1159
|
+
if (indexType)
|
|
1160
|
+
types.add(indexType);
|
|
1161
1161
|
}
|
|
1162
1162
|
return [...types];
|
|
1163
1163
|
}
|
|
1164
|
+
function referencedIndexEventTypes(subgraph) {
|
|
1165
|
+
return indexEventTypesForFilterTypes(sourceFilters(subgraph).map((f) => f.type));
|
|
1166
|
+
}
|
|
1164
1167
|
function isStreamsIndexEligible(subgraph) {
|
|
1165
1168
|
if (Array.isArray(subgraph.sources))
|
|
1166
1169
|
return false;
|
|
@@ -1422,6 +1425,8 @@ class SubscriptionMatcher {
|
|
|
1422
1425
|
for (const sub of subs) {
|
|
1423
1426
|
if (sub.status !== "active")
|
|
1424
1427
|
continue;
|
|
1428
|
+
if (sub.kind !== "subgraph" || !sub.subgraph_name || !sub.table_name)
|
|
1429
|
+
continue;
|
|
1425
1430
|
this.byId.set(sub.id, sub);
|
|
1426
1431
|
const k = key(sub.subgraph_name, sub.table_name);
|
|
1427
1432
|
const arr = this.byKey.get(k);
|
|
@@ -2491,8 +2496,8 @@ import { randomUUID } from "node:crypto";
|
|
|
2491
2496
|
import { hostname } from "node:os";
|
|
2492
2497
|
import { resolve } from "node:path";
|
|
2493
2498
|
import { pathToFileURL } from "node:url";
|
|
2494
|
-
import { getErrorMessage as
|
|
2495
|
-
import { getTargetDb as
|
|
2499
|
+
import { getErrorMessage as getErrorMessage6 } from "@secondlayer/shared";
|
|
2500
|
+
import { getTargetDb as getTargetDb8 } from "@secondlayer/shared/db";
|
|
2496
2501
|
import {
|
|
2497
2502
|
cancelSubgraphOperation,
|
|
2498
2503
|
claimSubgraphOperation,
|
|
@@ -2510,20 +2515,71 @@ import {
|
|
|
2510
2515
|
pgSchemaName as pgSchemaName2,
|
|
2511
2516
|
updateSubgraphStatus as updateSubgraphStatus3
|
|
2512
2517
|
} from "@secondlayer/shared/db/queries/subgraphs";
|
|
2513
|
-
import { logger as
|
|
2518
|
+
import { logger as logger14 } from "@secondlayer/shared/logger";
|
|
2514
2519
|
import { listen as listen2 } from "@secondlayer/shared/queue/listener";
|
|
2515
2520
|
|
|
2521
|
+
// src/runtime/chain-reorg.ts
|
|
2522
|
+
import { getTargetDb as getTargetDb5 } from "@secondlayer/shared/db";
|
|
2523
|
+
import { logger as logger9 } from "@secondlayer/shared/logger";
|
|
2524
|
+
var MAX_ORPHANED_PER_SUB = 500;
|
|
2525
|
+
async function handleChainReorg(forkHeight, db = getTargetDb5()) {
|
|
2526
|
+
await db.deleteFrom("subscription_outbox").where("kind", "=", "chain").where("block_height", ">=", forkHeight).where("status", "=", "pending").where("event_type", "like", "chain.%.apply").execute();
|
|
2527
|
+
const delivered = await db.selectFrom("subscription_outbox").select(["subscription_id", "tx_id", "payload"]).where("kind", "=", "chain").where("block_height", ">=", forkHeight).where("status", "=", "delivered").where("event_type", "like", "chain.%.apply").orderBy("block_height").orderBy("id").execute();
|
|
2528
|
+
const bySub = new Map;
|
|
2529
|
+
for (const row of delivered) {
|
|
2530
|
+
const list = bySub.get(row.subscription_id) ?? [];
|
|
2531
|
+
const payload = row.payload;
|
|
2532
|
+
list.push({ tx_id: row.tx_id, event: payload?.event ?? null });
|
|
2533
|
+
bySub.set(row.subscription_id, list);
|
|
2534
|
+
}
|
|
2535
|
+
if (bySub.size > 0) {
|
|
2536
|
+
const rows = [];
|
|
2537
|
+
for (const [subscriptionId, entries] of bySub) {
|
|
2538
|
+
const truncated = entries.length > MAX_ORPHANED_PER_SUB;
|
|
2539
|
+
const payload = {
|
|
2540
|
+
action: "rollback",
|
|
2541
|
+
fork_point_height: forkHeight,
|
|
2542
|
+
orphaned: truncated ? entries.slice(0, MAX_ORPHANED_PER_SUB) : entries,
|
|
2543
|
+
truncated
|
|
2544
|
+
};
|
|
2545
|
+
rows.push({
|
|
2546
|
+
subscription_id: subscriptionId,
|
|
2547
|
+
kind: "chain",
|
|
2548
|
+
subgraph_name: null,
|
|
2549
|
+
table_name: null,
|
|
2550
|
+
block_height: forkHeight,
|
|
2551
|
+
tx_id: null,
|
|
2552
|
+
row_pk: { fork_point_height: forkHeight },
|
|
2553
|
+
event_type: "chain.reorg.rollback",
|
|
2554
|
+
payload,
|
|
2555
|
+
dedup_key: `chainreorg:${subscriptionId}:${forkHeight}`
|
|
2556
|
+
});
|
|
2557
|
+
}
|
|
2558
|
+
await db.insertInto("subscription_outbox").values(rows).onConflict((oc) => oc.columns(["subscription_id", "dedup_key"]).doNothing()).execute();
|
|
2559
|
+
logger9.info("Chain reorg — emitted rollbacks", {
|
|
2560
|
+
forkPointHeight: forkHeight,
|
|
2561
|
+
subscriptions: bySub.size
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2564
|
+
await db.transaction().execute(async (trx) => {
|
|
2565
|
+
const cur = await trx.selectFrom("trigger_evaluator_state").select("last_processed_block").where("id", "=", true).forUpdate().executeTakeFirst();
|
|
2566
|
+
if (cur && Number(cur.last_processed_block) >= forkHeight) {
|
|
2567
|
+
await trx.updateTable("trigger_evaluator_state").set({ last_processed_block: forkHeight - 1, updated_at: new Date }).where("id", "=", true).execute();
|
|
2568
|
+
}
|
|
2569
|
+
});
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2516
2572
|
// src/runtime/emitter.ts
|
|
2517
2573
|
import {
|
|
2518
|
-
getTargetDb as
|
|
2574
|
+
getTargetDb as getTargetDb6
|
|
2519
2575
|
} from "@secondlayer/shared/db";
|
|
2520
2576
|
import { getSubscriptionSigningSecret } from "@secondlayer/shared/db/queries/subscriptions";
|
|
2521
|
-
import { logger as
|
|
2577
|
+
import { logger as logger11 } from "@secondlayer/shared/logger";
|
|
2522
2578
|
import { listen } from "@secondlayer/shared/queue/listener";
|
|
2523
2579
|
import { sql as sql4 } from "kysely";
|
|
2524
2580
|
|
|
2525
2581
|
// src/runtime/formats/index.ts
|
|
2526
|
-
import { logger as
|
|
2582
|
+
import { logger as logger10 } from "@secondlayer/shared/logger";
|
|
2527
2583
|
|
|
2528
2584
|
// src/runtime/formats/cloudevents.ts
|
|
2529
2585
|
function buildCloudEvents(outboxRow, _sub) {
|
|
@@ -2670,7 +2726,7 @@ function buildForFormat(outboxRow, sub, signingSecret) {
|
|
|
2670
2726
|
case "standard-webhooks":
|
|
2671
2727
|
return buildStandardWebhooks(outboxRow, signingSecret);
|
|
2672
2728
|
default:
|
|
2673
|
-
|
|
2729
|
+
logger10.warn("Unknown subscription format, falling back to standard-webhooks", {
|
|
2674
2730
|
format: sub.format,
|
|
2675
2731
|
subscriptionId: sub.id
|
|
2676
2732
|
});
|
|
@@ -2753,7 +2809,7 @@ async function dispatchOne(db, outboxRow, sub) {
|
|
|
2753
2809
|
let responseHeaders = {};
|
|
2754
2810
|
if (isPrivateEgress(sub.url) && !allowPrivateEgress()) {
|
|
2755
2811
|
error = "refused private egress (set SECONDLAYER_ALLOW_PRIVATE_EGRESS=true to allow)";
|
|
2756
|
-
|
|
2812
|
+
logger11.warn("[emitter] refused private egress", {
|
|
2757
2813
|
subscription: sub.name,
|
|
2758
2814
|
url: sub.url
|
|
2759
2815
|
});
|
|
@@ -2849,7 +2905,7 @@ async function settleFailed(db, outboxRow, sub, errText) {
|
|
|
2849
2905
|
circuit_opened_at: new Date,
|
|
2850
2906
|
updated_at: new Date
|
|
2851
2907
|
}).where("id", "=", sub.id).execute();
|
|
2852
|
-
|
|
2908
|
+
logger11.warn("Subscription circuit tripped — paused after consecutive failures", {
|
|
2853
2909
|
subscription: sub.name,
|
|
2854
2910
|
failures: newFailures
|
|
2855
2911
|
});
|
|
@@ -2937,7 +2993,7 @@ async function drainForSub(db, state, sub, rows) {
|
|
|
2937
2993
|
await settleFailed(db, row, sub, err);
|
|
2938
2994
|
}
|
|
2939
2995
|
} catch (err) {
|
|
2940
|
-
|
|
2996
|
+
logger11.error("Emitter dispatch crashed", {
|
|
2941
2997
|
outboxId: row.id,
|
|
2942
2998
|
error: err instanceof Error ? err.message : String(err)
|
|
2943
2999
|
});
|
|
@@ -2966,7 +3022,7 @@ async function runRetention(db) {
|
|
|
2966
3022
|
}
|
|
2967
3023
|
async function startEmitter(opts) {
|
|
2968
3024
|
const emitterId = `emitter-${Math.random().toString(36).slice(2, 10)}`;
|
|
2969
|
-
const db =
|
|
3025
|
+
const db = getTargetDb6();
|
|
2970
3026
|
const state = {
|
|
2971
3027
|
running: true,
|
|
2972
3028
|
inFlightBySub: new Map,
|
|
@@ -2974,7 +3030,7 @@ async function startEmitter(opts) {
|
|
|
2974
3030
|
};
|
|
2975
3031
|
const pollIntervalMs = opts?.pollIntervalMs ?? 120000;
|
|
2976
3032
|
const retentionIntervalMs = opts?.retentionIntervalMs ?? 60 * 60000;
|
|
2977
|
-
|
|
3033
|
+
logger11.info("[emitter] started", { id: emitterId });
|
|
2978
3034
|
const MATCHER_BOOT_ATTEMPTS = 5;
|
|
2979
3035
|
let lastErr = null;
|
|
2980
3036
|
for (let i = 0;i < MATCHER_BOOT_ATTEMPTS; i++) {
|
|
@@ -2985,7 +3041,7 @@ async function startEmitter(opts) {
|
|
|
2985
3041
|
} catch (err) {
|
|
2986
3042
|
lastErr = err;
|
|
2987
3043
|
const delayMs = 500 * 2 ** i;
|
|
2988
|
-
|
|
3044
|
+
logger11.warn("[emitter] matcher refresh failed, retrying", {
|
|
2989
3045
|
attempt: i + 1,
|
|
2990
3046
|
delayMs,
|
|
2991
3047
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -2999,21 +3055,21 @@ async function startEmitter(opts) {
|
|
|
2999
3055
|
const stopNew = await listen("subscriptions:new_outbox", () => {
|
|
3000
3056
|
if (!state.running)
|
|
3001
3057
|
return;
|
|
3002
|
-
claimAndDrain(db, state, emitterId).catch((err) =>
|
|
3058
|
+
claimAndDrain(db, state, emitterId).catch((err) => logger11.error("[emitter] claim failed", {
|
|
3003
3059
|
error: err instanceof Error ? err.message : String(err)
|
|
3004
3060
|
}));
|
|
3005
3061
|
});
|
|
3006
3062
|
const stopChanged = await listen("subscriptions:changed", () => {
|
|
3007
3063
|
if (!state.running)
|
|
3008
3064
|
return;
|
|
3009
|
-
refreshMatcher(db).catch((err) =>
|
|
3065
|
+
refreshMatcher(db).catch((err) => logger11.error("[emitter] matcher refresh failed", {
|
|
3010
3066
|
error: err instanceof Error ? err.message : String(err)
|
|
3011
3067
|
}));
|
|
3012
3068
|
});
|
|
3013
3069
|
const poll = setInterval(() => {
|
|
3014
3070
|
if (!state.running)
|
|
3015
3071
|
return;
|
|
3016
|
-
claimAndDrain(db, state, emitterId).catch((err) =>
|
|
3072
|
+
claimAndDrain(db, state, emitterId).catch((err) => logger11.error("[emitter] poll claim failed", {
|
|
3017
3073
|
error: err instanceof Error ? err.message : String(err)
|
|
3018
3074
|
}));
|
|
3019
3075
|
}, pollIntervalMs);
|
|
@@ -3021,7 +3077,7 @@ async function startEmitter(opts) {
|
|
|
3021
3077
|
const retention = setInterval(() => {
|
|
3022
3078
|
if (!state.running)
|
|
3023
3079
|
return;
|
|
3024
|
-
runRetention(db).catch((err) =>
|
|
3080
|
+
runRetention(db).catch((err) => logger11.error("[emitter] retention failed", {
|
|
3025
3081
|
error: err instanceof Error ? err.message : String(err)
|
|
3026
3082
|
}));
|
|
3027
3083
|
}, retentionIntervalMs);
|
|
@@ -3031,28 +3087,30 @@ async function startEmitter(opts) {
|
|
|
3031
3087
|
clearInterval(retention);
|
|
3032
3088
|
await stopNew();
|
|
3033
3089
|
await stopChanged();
|
|
3034
|
-
|
|
3090
|
+
logger11.info("[emitter] stopped", { id: emitterId });
|
|
3035
3091
|
};
|
|
3036
3092
|
}
|
|
3037
3093
|
|
|
3038
3094
|
// src/runtime/streams-reorg-poll.ts
|
|
3039
3095
|
import { getErrorMessage as getErrorMessage4 } from "@secondlayer/shared";
|
|
3040
3096
|
import { IndexHttpClient as IndexHttpClient2 } from "@secondlayer/shared/index-http";
|
|
3041
|
-
import { logger as
|
|
3097
|
+
import { logger as logger12 } from "@secondlayer/shared/logger";
|
|
3042
3098
|
var POLL_MS = Number(process.env.SUBGRAPH_REORG_POLL_MS) || 15000;
|
|
3043
3099
|
var STARTUP_MARGIN_MS = 60 * 60 * 1000;
|
|
3044
|
-
async function pollReorgsOnce(http, cursor, handleReorg, loadDef) {
|
|
3100
|
+
async function pollReorgsOnce(http, cursor, handleReorg, loadDef, handleChainReorg2) {
|
|
3045
3101
|
const { reorgs, next_since } = await http.listReorgs(cursor);
|
|
3046
3102
|
const sorted = [...reorgs].sort((a, b) => a.fork_point_height - b.fork_point_height);
|
|
3047
3103
|
for (const r of sorted) {
|
|
3048
|
-
|
|
3104
|
+
logger12.info("Streams reorg — rewinding subgraphs", {
|
|
3049
3105
|
forkPointHeight: r.fork_point_height
|
|
3050
3106
|
});
|
|
3051
3107
|
await handleReorg(r.fork_point_height, loadDef);
|
|
3108
|
+
if (handleChainReorg2)
|
|
3109
|
+
await handleChainReorg2(r.fork_point_height);
|
|
3052
3110
|
}
|
|
3053
3111
|
return next_since ?? cursor;
|
|
3054
3112
|
}
|
|
3055
|
-
function startStreamsReorgPoll(handleReorg, loadDef) {
|
|
3113
|
+
function startStreamsReorgPoll(handleReorg, loadDef, handleChainReorg2) {
|
|
3056
3114
|
const baseUrl = process.env.SUBGRAPH_INDEX_API_URL ?? process.env.STREAMS_API_URL ?? "http://api:3800";
|
|
3057
3115
|
const http = new IndexHttpClient2({
|
|
3058
3116
|
indexBaseUrl: baseUrl,
|
|
@@ -3066,9 +3124,9 @@ function startStreamsReorgPoll(handleReorg, loadDef) {
|
|
|
3066
3124
|
if (!running)
|
|
3067
3125
|
return;
|
|
3068
3126
|
try {
|
|
3069
|
-
since = await pollReorgsOnce(http, since, handleReorg, loadDef);
|
|
3127
|
+
since = await pollReorgsOnce(http, since, handleReorg, loadDef, handleChainReorg2);
|
|
3070
3128
|
} catch (err) {
|
|
3071
|
-
|
|
3129
|
+
logger12.error("Streams reorg poll failed", {
|
|
3072
3130
|
error: getErrorMessage4(err)
|
|
3073
3131
|
});
|
|
3074
3132
|
}
|
|
@@ -3076,7 +3134,222 @@ function startStreamsReorgPoll(handleReorg, loadDef) {
|
|
|
3076
3134
|
timer = setTimeout(tick, POLL_MS);
|
|
3077
3135
|
};
|
|
3078
3136
|
timer = setTimeout(tick, POLL_MS);
|
|
3079
|
-
|
|
3137
|
+
logger12.info("Streams reorg poll started", { pollMs: POLL_MS });
|
|
3138
|
+
return () => {
|
|
3139
|
+
running = false;
|
|
3140
|
+
if (timer)
|
|
3141
|
+
clearTimeout(timer);
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
|
|
3145
|
+
// src/runtime/trigger-evaluator-loop.ts
|
|
3146
|
+
import { getErrorMessage as getErrorMessage5 } from "@secondlayer/shared";
|
|
3147
|
+
import { getTargetDb as getTargetDb7 } from "@secondlayer/shared/db";
|
|
3148
|
+
import { listActiveChainSubscriptions } from "@secondlayer/shared/db/queries/subscriptions";
|
|
3149
|
+
import { logger as logger13 } from "@secondlayer/shared/logger";
|
|
3150
|
+
|
|
3151
|
+
// src/runtime/trigger-evaluator.ts
|
|
3152
|
+
import { resolveTraitContractIds as resolveTraitContractIds2 } from "@secondlayer/shared/db/queries/contracts";
|
|
3153
|
+
var TX_LEVEL_TRIGGER_TYPES = new Set(["contract_call", "contract_deploy"]);
|
|
3154
|
+
function sourceKey(subscriptionId, triggerIndex) {
|
|
3155
|
+
return `${subscriptionId}#${triggerIndex}`;
|
|
3156
|
+
}
|
|
3157
|
+
function toAmount(v) {
|
|
3158
|
+
return v === undefined ? undefined : BigInt(v);
|
|
3159
|
+
}
|
|
3160
|
+
function chainTriggerToFilter(trigger) {
|
|
3161
|
+
const t = trigger;
|
|
3162
|
+
const filter = { ...trigger };
|
|
3163
|
+
const minAmount = toAmount(t.minAmount);
|
|
3164
|
+
const maxAmount = toAmount(t.maxAmount);
|
|
3165
|
+
if (minAmount !== undefined)
|
|
3166
|
+
filter.minAmount = minAmount;
|
|
3167
|
+
if (maxAmount !== undefined)
|
|
3168
|
+
filter.maxAmount = maxAmount;
|
|
3169
|
+
return filter;
|
|
3170
|
+
}
|
|
3171
|
+
function triggersOf(sub) {
|
|
3172
|
+
return sub.triggers ?? [];
|
|
3173
|
+
}
|
|
3174
|
+
function buildSourcesMap(chainSubs) {
|
|
3175
|
+
const sources = {};
|
|
3176
|
+
const keyMeta = new Map;
|
|
3177
|
+
for (const sub of chainSubs) {
|
|
3178
|
+
triggersOf(sub).forEach((trigger, triggerIndex) => {
|
|
3179
|
+
const key2 = sourceKey(sub.id, triggerIndex);
|
|
3180
|
+
sources[key2] = chainTriggerToFilter(trigger);
|
|
3181
|
+
keyMeta.set(key2, {
|
|
3182
|
+
subscriptionId: sub.id,
|
|
3183
|
+
triggerIndex,
|
|
3184
|
+
triggerType: trigger.type
|
|
3185
|
+
});
|
|
3186
|
+
});
|
|
3187
|
+
}
|
|
3188
|
+
return { sources, keyMeta };
|
|
3189
|
+
}
|
|
3190
|
+
function referencedEventTypes(chainSubs) {
|
|
3191
|
+
const filterTypes = new Set;
|
|
3192
|
+
for (const sub of chainSubs) {
|
|
3193
|
+
for (const trigger of triggersOf(sub))
|
|
3194
|
+
filterTypes.add(trigger.type);
|
|
3195
|
+
}
|
|
3196
|
+
return indexEventTypesForFilterTypes([...filterTypes]);
|
|
3197
|
+
}
|
|
3198
|
+
function referencedTraits(chainSubs) {
|
|
3199
|
+
const traits = new Set;
|
|
3200
|
+
for (const sub of chainSubs) {
|
|
3201
|
+
for (const trigger of triggersOf(sub)) {
|
|
3202
|
+
const trait = trigger.trait;
|
|
3203
|
+
if (trait)
|
|
3204
|
+
traits.add(trait);
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
return [...traits];
|
|
3208
|
+
}
|
|
3209
|
+
async function buildTraitContracts(db, chainSubs, asOfBlock) {
|
|
3210
|
+
const resolved = new Map;
|
|
3211
|
+
for (const trait of referencedTraits(chainSubs)) {
|
|
3212
|
+
const ids = await resolveTraitContractIds2(db, trait, asOfBlock);
|
|
3213
|
+
resolved.set(trait, new Set(ids));
|
|
3214
|
+
}
|
|
3215
|
+
return resolved;
|
|
3216
|
+
}
|
|
3217
|
+
function evaluateBlock(block, sources, traitContracts) {
|
|
3218
|
+
return matchSources(sources, block.txs, block.events, traitContracts);
|
|
3219
|
+
}
|
|
3220
|
+
function chainDedupKey(subscriptionId, txId, eventIndex, blockHash) {
|
|
3221
|
+
return `chain:${subscriptionId}:${txId}:${eventIndex}:${blockHash}`;
|
|
3222
|
+
}
|
|
3223
|
+
function applyRow(meta, blockHeight, blockHash, txId, eventIndex, event) {
|
|
3224
|
+
const payload = {
|
|
3225
|
+
action: "apply",
|
|
3226
|
+
block_hash: blockHash,
|
|
3227
|
+
block_height: blockHeight,
|
|
3228
|
+
tx_id: txId,
|
|
3229
|
+
canonical: true,
|
|
3230
|
+
trigger: meta.triggerType,
|
|
3231
|
+
event
|
|
3232
|
+
};
|
|
3233
|
+
return {
|
|
3234
|
+
subscription_id: meta.subscriptionId,
|
|
3235
|
+
kind: "chain",
|
|
3236
|
+
subgraph_name: null,
|
|
3237
|
+
table_name: null,
|
|
3238
|
+
block_height: blockHeight,
|
|
3239
|
+
tx_id: txId,
|
|
3240
|
+
row_pk: { tx_id: txId, event_index: eventIndex },
|
|
3241
|
+
event_type: `chain.${meta.triggerType}.apply`,
|
|
3242
|
+
payload,
|
|
3243
|
+
dedup_key: chainDedupKey(meta.subscriptionId, txId, eventIndex, blockHash)
|
|
3244
|
+
};
|
|
3245
|
+
}
|
|
3246
|
+
async function emitChainOutbox(db, matches, keyMeta, blockHeight, blockHash) {
|
|
3247
|
+
const rows = [];
|
|
3248
|
+
for (const match of matches) {
|
|
3249
|
+
const meta = keyMeta.get(match.sourceName);
|
|
3250
|
+
if (!meta)
|
|
3251
|
+
continue;
|
|
3252
|
+
const txId = match.tx.tx_id;
|
|
3253
|
+
if (TX_LEVEL_TRIGGER_TYPES.has(meta.triggerType)) {
|
|
3254
|
+
rows.push(applyRow(meta, blockHeight, blockHash, txId, -1, {
|
|
3255
|
+
tx_id: txId,
|
|
3256
|
+
type: match.tx.type,
|
|
3257
|
+
sender: match.tx.sender,
|
|
3258
|
+
status: match.tx.status,
|
|
3259
|
+
contract_id: match.tx.contract_id ?? null,
|
|
3260
|
+
function_name: match.tx.function_name ?? null,
|
|
3261
|
+
function_args: match.tx.function_args ?? null,
|
|
3262
|
+
result_hex: match.tx.raw_result ?? null
|
|
3263
|
+
}));
|
|
3264
|
+
} else {
|
|
3265
|
+
for (const event of match.events) {
|
|
3266
|
+
rows.push(applyRow(meta, blockHeight, blockHash, txId, event.event_index, {
|
|
3267
|
+
tx_id: txId,
|
|
3268
|
+
type: event.type,
|
|
3269
|
+
event_index: event.event_index,
|
|
3270
|
+
data: event.data
|
|
3271
|
+
}));
|
|
3272
|
+
}
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
if (rows.length === 0)
|
|
3276
|
+
return 0;
|
|
3277
|
+
await db.insertInto("subscription_outbox").values(rows).onConflict((oc) => oc.columns(["subscription_id", "dedup_key"]).doNothing()).execute();
|
|
3278
|
+
return rows.length;
|
|
3279
|
+
}
|
|
3280
|
+
|
|
3281
|
+
// src/runtime/trigger-evaluator-loop.ts
|
|
3282
|
+
var POLL_MS2 = Number(process.env.TRIGGER_EVALUATOR_POLL_MS) || 5000;
|
|
3283
|
+
var BATCH = Number(process.env.TRIGGER_EVALUATOR_BATCH) || 200;
|
|
3284
|
+
var MAX_BLOCKS_PER_TICK = Number(process.env.TRIGGER_EVALUATOR_MAX_BLOCKS) || 2000;
|
|
3285
|
+
async function readCursor(db) {
|
|
3286
|
+
const row = await db.selectFrom("trigger_evaluator_state").select("last_processed_block").where("id", "=", true).executeTakeFirst();
|
|
3287
|
+
return row ? Number(row.last_processed_block) : 0;
|
|
3288
|
+
}
|
|
3289
|
+
async function advanceCursor(db, to) {
|
|
3290
|
+
await db.transaction().execute(async (trx) => {
|
|
3291
|
+
const cur = await trx.selectFrom("trigger_evaluator_state").select("last_processed_block").where("id", "=", true).forUpdate().executeTakeFirst();
|
|
3292
|
+
if (cur && Number(cur.last_processed_block) < to) {
|
|
3293
|
+
await trx.updateTable("trigger_evaluator_state").set({ last_processed_block: to, updated_at: new Date }).where("id", "=", true).execute();
|
|
3294
|
+
}
|
|
3295
|
+
});
|
|
3296
|
+
}
|
|
3297
|
+
async function runEvaluatorOnce(db = getTargetDb7()) {
|
|
3298
|
+
const chainSubs = await listActiveChainSubscriptions(db);
|
|
3299
|
+
const source = new PublicApiBlockSource(buildHttpClient(), referencedEventTypes(chainSubs));
|
|
3300
|
+
const tip = await source.getTip();
|
|
3301
|
+
if (tip <= 0)
|
|
3302
|
+
return 0;
|
|
3303
|
+
const cursor = await readCursor(db);
|
|
3304
|
+
if (cursor === 0 || chainSubs.length === 0) {
|
|
3305
|
+
await advanceCursor(db, tip);
|
|
3306
|
+
return 0;
|
|
3307
|
+
}
|
|
3308
|
+
if (cursor >= tip)
|
|
3309
|
+
return 0;
|
|
3310
|
+
const { sources, keyMeta } = buildSourcesMap(chainSubs);
|
|
3311
|
+
const target = Math.min(tip, cursor + MAX_BLOCKS_PER_TICK);
|
|
3312
|
+
let emitted = 0;
|
|
3313
|
+
for (let from = cursor + 1;from <= target; from = from + BATCH) {
|
|
3314
|
+
const to = Math.min(from + BATCH - 1, target);
|
|
3315
|
+
const blocks = await source.loadBlockRange(from, to);
|
|
3316
|
+
const traitContracts = await buildTraitContracts(db, chainSubs, to);
|
|
3317
|
+
for (let h = from;h <= to; h++) {
|
|
3318
|
+
const bd = blocks.get(h);
|
|
3319
|
+
if (!bd)
|
|
3320
|
+
continue;
|
|
3321
|
+
const matches = evaluateBlock(bd, sources, traitContracts);
|
|
3322
|
+
if (matches.length === 0)
|
|
3323
|
+
continue;
|
|
3324
|
+
emitted += await emitChainOutbox(db, matches, keyMeta, h, bd.block.hash);
|
|
3325
|
+
}
|
|
3326
|
+
await advanceCursor(db, to);
|
|
3327
|
+
}
|
|
3328
|
+
return emitted;
|
|
3329
|
+
}
|
|
3330
|
+
function startTriggerEvaluator() {
|
|
3331
|
+
let running = true;
|
|
3332
|
+
let timer;
|
|
3333
|
+
const tick = async () => {
|
|
3334
|
+
if (!running)
|
|
3335
|
+
return;
|
|
3336
|
+
try {
|
|
3337
|
+
const emitted = await runEvaluatorOnce();
|
|
3338
|
+
if (emitted > 0) {
|
|
3339
|
+
logger13.info("Trigger evaluator emitted chain deliveries", {
|
|
3340
|
+
count: emitted
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
} catch (err) {
|
|
3344
|
+
logger13.error("Trigger evaluator tick failed", {
|
|
3345
|
+
error: getErrorMessage5(err)
|
|
3346
|
+
});
|
|
3347
|
+
}
|
|
3348
|
+
if (running)
|
|
3349
|
+
timer = setTimeout(tick, POLL_MS2);
|
|
3350
|
+
};
|
|
3351
|
+
timer = setTimeout(tick, POLL_MS2);
|
|
3352
|
+
logger13.info("Trigger evaluator started", { pollMs: POLL_MS2 });
|
|
3080
3353
|
return () => {
|
|
3081
3354
|
running = false;
|
|
3082
3355
|
if (timer)
|
|
@@ -3103,11 +3376,11 @@ async function catchUpAll(subgraphs, db, concurrency) {
|
|
|
3103
3376
|
const def = await loadSubgraphDefinition(sg);
|
|
3104
3377
|
await catchUpSubgraph(def, sg.name);
|
|
3105
3378
|
} catch (err) {
|
|
3106
|
-
const msg =
|
|
3379
|
+
const msg = getErrorMessage6(err);
|
|
3107
3380
|
if (isHandlerNotFoundError(err)) {
|
|
3108
3381
|
await updateSubgraphStatus3(db, sg.name, "error");
|
|
3109
3382
|
}
|
|
3110
|
-
|
|
3383
|
+
logger14.error("Subgraph catch-up failed", {
|
|
3111
3384
|
subgraph: sg.name,
|
|
3112
3385
|
error: msg
|
|
3113
3386
|
});
|
|
@@ -3153,7 +3426,7 @@ async function loadSubgraphDefinition(sg) {
|
|
|
3153
3426
|
definitionCache.set(sg.name, def);
|
|
3154
3427
|
if (prevVersion && prevVersion !== sg.version) {
|
|
3155
3428
|
invalidateSubgraphRoute(sg.name);
|
|
3156
|
-
|
|
3429
|
+
logger14.info("Subgraph handler reloaded", {
|
|
3157
3430
|
subgraph: sg.name,
|
|
3158
3431
|
from: prevVersion,
|
|
3159
3432
|
to: sg.version
|
|
@@ -3172,7 +3445,7 @@ function cleanupCaches(active) {
|
|
|
3172
3445
|
}
|
|
3173
3446
|
}
|
|
3174
3447
|
async function synthesizeLegacyReindexOperations() {
|
|
3175
|
-
const db =
|
|
3448
|
+
const db = getTargetDb8();
|
|
3176
3449
|
const stale = (await listSubgraphs2(db)).filter((sg) => sg.status === "reindexing");
|
|
3177
3450
|
for (const sg of stale) {
|
|
3178
3451
|
const active = await findActiveSubgraphOperation(db, sg.id);
|
|
@@ -3187,7 +3460,7 @@ async function synthesizeLegacyReindexOperations() {
|
|
|
3187
3460
|
fromBlock: sg.reindex_from_block == null ? undefined : Number(sg.reindex_from_block),
|
|
3188
3461
|
toBlock: sg.reindex_to_block == null ? undefined : Number(sg.reindex_to_block)
|
|
3189
3462
|
});
|
|
3190
|
-
|
|
3463
|
+
logger14.info("Queued legacy reindex resume operation", {
|
|
3191
3464
|
subgraph: sg.name
|
|
3192
3465
|
});
|
|
3193
3466
|
} catch (err) {
|
|
@@ -3201,7 +3474,7 @@ async function runSubgraphOperation(operation, signal) {
|
|
|
3201
3474
|
if (operation.cancel_requested) {
|
|
3202
3475
|
return 0;
|
|
3203
3476
|
}
|
|
3204
|
-
const db =
|
|
3477
|
+
const db = getTargetDb8();
|
|
3205
3478
|
const subgraph = await db.selectFrom("subgraphs").selectAll().where("id", "=", operation.subgraph_id).executeTakeFirst();
|
|
3206
3479
|
if (!subgraph)
|
|
3207
3480
|
throw new Error(`Subgraph not found: ${operation.subgraph_id}`);
|
|
@@ -3237,13 +3510,13 @@ async function runSubgraphOperation(operation, signal) {
|
|
|
3237
3510
|
}
|
|
3238
3511
|
async function startSubgraphOperationRunner(opts) {
|
|
3239
3512
|
const concurrency = opts?.concurrency ?? DEFAULT_OPERATION_CONCURRENCY;
|
|
3240
|
-
const db =
|
|
3513
|
+
const db = getTargetDb8();
|
|
3241
3514
|
const lockedBy = `${hostname()}:${process.pid}:${randomUUID()}`;
|
|
3242
3515
|
const active = new Map;
|
|
3243
3516
|
const activeRuns = new Map;
|
|
3244
3517
|
let running = true;
|
|
3245
3518
|
let draining = false;
|
|
3246
|
-
|
|
3519
|
+
logger14.info("Starting subgraph operation runner", { concurrency, lockedBy });
|
|
3247
3520
|
const startOperation = (operation) => {
|
|
3248
3521
|
const controller = new AbortController;
|
|
3249
3522
|
active.set(operation.id, controller);
|
|
@@ -3251,9 +3524,9 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3251
3524
|
if (!running)
|
|
3252
3525
|
return;
|
|
3253
3526
|
heartbeatSubgraphOperation(db, operation.id, lockedBy).catch((err) => {
|
|
3254
|
-
|
|
3527
|
+
logger14.warn("Subgraph operation heartbeat failed", {
|
|
3255
3528
|
operationId: operation.id,
|
|
3256
|
-
error:
|
|
3529
|
+
error: getErrorMessage6(err)
|
|
3257
3530
|
});
|
|
3258
3531
|
});
|
|
3259
3532
|
}, HEARTBEAT_INTERVAL_MS);
|
|
@@ -3263,9 +3536,9 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3263
3536
|
controller.abort("user-cancelled");
|
|
3264
3537
|
}
|
|
3265
3538
|
}).catch((err) => {
|
|
3266
|
-
|
|
3539
|
+
logger14.warn("Subgraph operation cancel poll failed", {
|
|
3267
3540
|
operationId: operation.id,
|
|
3268
|
-
error:
|
|
3541
|
+
error: getErrorMessage6(err)
|
|
3269
3542
|
});
|
|
3270
3543
|
});
|
|
3271
3544
|
}, CANCEL_POLL_INTERVAL_MS);
|
|
@@ -3280,14 +3553,14 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3280
3553
|
const reason = String(controller.signal.reason ?? "");
|
|
3281
3554
|
if (controller.signal.aborted && reason === "user-cancelled") {
|
|
3282
3555
|
await cancelSubgraphOperation(db, operation.id, lockedBy, processed);
|
|
3283
|
-
|
|
3556
|
+
logger14.info("Subgraph operation cancelled", {
|
|
3284
3557
|
operationId: operation.id,
|
|
3285
3558
|
subgraph: operation.subgraph_name
|
|
3286
3559
|
});
|
|
3287
3560
|
return;
|
|
3288
3561
|
}
|
|
3289
3562
|
if (controller.signal.aborted) {
|
|
3290
|
-
|
|
3563
|
+
logger14.info("Subgraph operation interrupted", {
|
|
3291
3564
|
operationId: operation.id,
|
|
3292
3565
|
subgraph: operation.subgraph_name,
|
|
3293
3566
|
reason
|
|
@@ -3295,7 +3568,7 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3295
3568
|
return;
|
|
3296
3569
|
}
|
|
3297
3570
|
await completeSubgraphOperation(db, operation.id, lockedBy, processed);
|
|
3298
|
-
|
|
3571
|
+
logger14.info("Subgraph operation completed", {
|
|
3299
3572
|
operationId: operation.id,
|
|
3300
3573
|
subgraph: operation.subgraph_name,
|
|
3301
3574
|
processed
|
|
@@ -3303,7 +3576,7 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3303
3576
|
} catch (err) {
|
|
3304
3577
|
const reason = String(controller.signal.reason ?? "");
|
|
3305
3578
|
if (controller.signal.aborted && reason === "shutdown") {
|
|
3306
|
-
|
|
3579
|
+
logger14.info("Subgraph operation interrupted by shutdown", {
|
|
3307
3580
|
operationId: operation.id,
|
|
3308
3581
|
subgraph: operation.subgraph_name
|
|
3309
3582
|
});
|
|
@@ -3313,11 +3586,11 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3313
3586
|
await cancelSubgraphOperation(db, operation.id, lockedBy, processed);
|
|
3314
3587
|
return;
|
|
3315
3588
|
}
|
|
3316
|
-
await failSubgraphOperation(db, operation.id, lockedBy,
|
|
3317
|
-
|
|
3589
|
+
await failSubgraphOperation(db, operation.id, lockedBy, getErrorMessage6(err), processed);
|
|
3590
|
+
logger14.error("Subgraph operation failed", {
|
|
3318
3591
|
operationId: operation.id,
|
|
3319
3592
|
subgraph: operation.subgraph_name,
|
|
3320
|
-
error:
|
|
3593
|
+
error: getErrorMessage6(err)
|
|
3321
3594
|
});
|
|
3322
3595
|
} finally {
|
|
3323
3596
|
clearInterval(heartbeat);
|
|
@@ -3361,23 +3634,23 @@ async function startSubgraphOperationRunner(opts) {
|
|
|
3361
3634
|
controller.abort("shutdown");
|
|
3362
3635
|
}
|
|
3363
3636
|
await Promise.allSettled(activeRuns.values());
|
|
3364
|
-
|
|
3637
|
+
logger14.info("Subgraph operation runner stopped");
|
|
3365
3638
|
};
|
|
3366
3639
|
}
|
|
3367
3640
|
async function startSubgraphProcessor(opts) {
|
|
3368
3641
|
const concurrency = opts?.concurrency ?? DEFAULT_CONCURRENCY;
|
|
3369
3642
|
let running = true;
|
|
3370
|
-
|
|
3643
|
+
logger14.info("Starting subgraph processor", { concurrency });
|
|
3371
3644
|
const stopOperations = await startSubgraphOperationRunner({
|
|
3372
3645
|
concurrency: Number.parseInt(process.env.SUBGRAPH_OPERATION_CONCURRENCY ?? String(DEFAULT_OPERATION_CONCURRENCY))
|
|
3373
3646
|
});
|
|
3374
|
-
const targetDb =
|
|
3647
|
+
const targetDb = getTargetDb8();
|
|
3375
3648
|
const activeSubgraphs = (await listSubgraphs2(targetDb)).filter((v) => v.status === "active");
|
|
3376
3649
|
await catchUpAll(activeSubgraphs, targetDb, concurrency);
|
|
3377
3650
|
const stopListening = await listen2(CHANNEL_NEW_BLOCK, async () => {
|
|
3378
3651
|
if (!running)
|
|
3379
3652
|
return;
|
|
3380
|
-
const db =
|
|
3653
|
+
const db = getTargetDb8();
|
|
3381
3654
|
const subgraphs = (await listSubgraphs2(db)).filter((v) => v.status === "active");
|
|
3382
3655
|
cleanupCaches(subgraphs);
|
|
3383
3656
|
await catchUpAll(subgraphs, db, concurrency);
|
|
@@ -3392,37 +3665,39 @@ async function startSubgraphProcessor(opts) {
|
|
|
3392
3665
|
await handleSubgraphReorg(blockHeight, loadSubgraphDefinition);
|
|
3393
3666
|
}
|
|
3394
3667
|
} catch (err) {
|
|
3395
|
-
|
|
3396
|
-
error:
|
|
3668
|
+
logger14.error("Subgraph reorg handling failed", {
|
|
3669
|
+
error: getErrorMessage6(err)
|
|
3397
3670
|
});
|
|
3398
3671
|
}
|
|
3399
3672
|
}, { connectionString: sourceListenerUrl() });
|
|
3400
3673
|
const pollInterval = setInterval(async () => {
|
|
3401
3674
|
if (!running)
|
|
3402
3675
|
return;
|
|
3403
|
-
const db =
|
|
3676
|
+
const db = getTargetDb8();
|
|
3404
3677
|
const subgraphs = (await listSubgraphs2(db)).filter((v) => v.status === "active");
|
|
3405
3678
|
cleanupCaches(subgraphs);
|
|
3406
3679
|
await catchUpAll(subgraphs, db, concurrency);
|
|
3407
3680
|
}, POLL_INTERVAL_MS);
|
|
3408
|
-
const stopStreamsReorgPoll = process.env.SUBGRAPH_SOURCE === "streams-index" ? startStreamsReorgPoll(handleSubgraphReorg, loadSubgraphDefinition) : undefined;
|
|
3681
|
+
const stopStreamsReorgPoll = process.env.SUBGRAPH_SOURCE === "streams-index" ? startStreamsReorgPoll(handleSubgraphReorg, loadSubgraphDefinition, (forkHeight) => handleChainReorg(forkHeight)) : undefined;
|
|
3682
|
+
const stopTriggerEvaluator = process.env.SUBGRAPH_SOURCE === "streams-index" ? startTriggerEvaluator() : undefined;
|
|
3409
3683
|
const stopEmitter = await startEmitter();
|
|
3410
|
-
|
|
3684
|
+
logger14.info("Subgraph processor ready");
|
|
3411
3685
|
return async () => {
|
|
3412
3686
|
running = false;
|
|
3413
3687
|
clearInterval(pollInterval);
|
|
3414
3688
|
await stopListening();
|
|
3415
3689
|
await stopReorgListening();
|
|
3416
3690
|
stopStreamsReorgPoll?.();
|
|
3691
|
+
stopTriggerEvaluator?.();
|
|
3417
3692
|
await stopOperations();
|
|
3418
3693
|
await stopEmitter();
|
|
3419
|
-
|
|
3694
|
+
logger14.info("Subgraph processor stopped");
|
|
3420
3695
|
};
|
|
3421
3696
|
}
|
|
3422
3697
|
|
|
3423
3698
|
// src/service.ts
|
|
3424
3699
|
import { getDb } from "@secondlayer/shared/db";
|
|
3425
|
-
import { logger as
|
|
3700
|
+
import { logger as logger15 } from "@secondlayer/shared/logger";
|
|
3426
3701
|
import { sql as sql5 } from "kysely";
|
|
3427
3702
|
var HEARTBEAT_INTERVAL_MS2 = 30000;
|
|
3428
3703
|
var SERVICE_NAME = "subgraph-processor";
|
|
@@ -3430,7 +3705,7 @@ async function writeHeartbeat() {
|
|
|
3430
3705
|
try {
|
|
3431
3706
|
await getDb().insertInto("service_heartbeats").values({ name: SERVICE_NAME }).onConflict((oc) => oc.column("name").doUpdateSet({ updated_at: sql5`now()` })).execute();
|
|
3432
3707
|
} catch (err) {
|
|
3433
|
-
|
|
3708
|
+
logger15.warn("subgraph-processor heartbeat write failed", {
|
|
3434
3709
|
error: err instanceof Error ? err.message : String(err)
|
|
3435
3710
|
});
|
|
3436
3711
|
}
|
|
@@ -3441,7 +3716,7 @@ var processor = await startSubgraphProcessor({
|
|
|
3441
3716
|
await writeHeartbeat();
|
|
3442
3717
|
var heartbeatInterval = setInterval(writeHeartbeat, HEARTBEAT_INTERVAL_MS2);
|
|
3443
3718
|
var shutdown = async () => {
|
|
3444
|
-
|
|
3719
|
+
logger15.info("Shutting down subgraph processor...");
|
|
3445
3720
|
clearInterval(heartbeatInterval);
|
|
3446
3721
|
await processor();
|
|
3447
3722
|
process.exit(0);
|
|
@@ -3449,5 +3724,5 @@ var shutdown = async () => {
|
|
|
3449
3724
|
process.on("SIGINT", shutdown);
|
|
3450
3725
|
process.on("SIGTERM", shutdown);
|
|
3451
3726
|
|
|
3452
|
-
//# debugId=
|
|
3727
|
+
//# debugId=4BE2D954B659151B64756E2164756E21
|
|
3453
3728
|
//# sourceMappingURL=service.js.map
|