@thru/indexer 0.2.31 → 0.2.33
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/index.cjs +211 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.mjs +212 -64
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -301,6 +301,54 @@ function getSchemaExports(config) {
|
|
|
301
301
|
return exports;
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
+
// src/runtime/logger.ts
|
|
305
|
+
var LEVELS = ["debug", "info", "warn", "error"];
|
|
306
|
+
function shouldLog(level, minimum) {
|
|
307
|
+
return LEVELS.indexOf(level) >= LEVELS.indexOf(minimum);
|
|
308
|
+
}
|
|
309
|
+
function writeConsole(prefix, level, message, meta) {
|
|
310
|
+
const text3 = `[${prefix}] ${message}`;
|
|
311
|
+
if (meta && Object.keys(meta).length > 0) {
|
|
312
|
+
if (level === "error") {
|
|
313
|
+
console.error(text3, meta);
|
|
314
|
+
} else if (level === "warn") {
|
|
315
|
+
console.warn(text3, meta);
|
|
316
|
+
} else {
|
|
317
|
+
console.log(text3, meta);
|
|
318
|
+
}
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (level === "error") {
|
|
322
|
+
console.error(text3);
|
|
323
|
+
} else if (level === "warn") {
|
|
324
|
+
console.warn(text3);
|
|
325
|
+
} else {
|
|
326
|
+
console.log(text3);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function createScopedLogger(options) {
|
|
330
|
+
const minimum = options.level ?? "info";
|
|
331
|
+
const bindings = options.bindings ?? {};
|
|
332
|
+
const log = (level, message, meta) => {
|
|
333
|
+
if (!shouldLog(level, minimum)) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const hasMeta = meta !== void 0 && Object.keys(meta).length > 0;
|
|
337
|
+
const fields = { ...bindings, ...meta ?? {} };
|
|
338
|
+
if (options.logger) {
|
|
339
|
+
options.logger[level](message, fields);
|
|
340
|
+
} else {
|
|
341
|
+
writeConsole(options.prefix, level, message, hasMeta ? fields : void 0);
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
return {
|
|
345
|
+
debug: (message, meta) => log("debug", message, meta),
|
|
346
|
+
info: (message, meta) => log("info", message, meta),
|
|
347
|
+
warn: (message, meta) => log("warn", message, meta),
|
|
348
|
+
error: (message, meta) => log("error", message, meta)
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
304
352
|
// src/streams/processor.ts
|
|
305
353
|
var StreamBatcher = class {
|
|
306
354
|
currentSlot = null;
|
|
@@ -360,14 +408,21 @@ async function runEventStreamProcessor(stream, options, abortSignal) {
|
|
|
360
408
|
safetyMargin = 64,
|
|
361
409
|
pageSize = 512,
|
|
362
410
|
logLevel = "info",
|
|
411
|
+
logger: baseLogger,
|
|
363
412
|
validateParse = false,
|
|
364
413
|
observer
|
|
365
414
|
} = options;
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
415
|
+
const logger = createScopedLogger({
|
|
416
|
+
logger: baseLogger,
|
|
417
|
+
level: logLevel,
|
|
418
|
+
prefix: stream.name,
|
|
419
|
+
bindings: {
|
|
420
|
+
component: "indexer-stream",
|
|
421
|
+
stream: stream.name,
|
|
422
|
+
kind: "event"
|
|
369
423
|
}
|
|
370
|
-
};
|
|
424
|
+
});
|
|
425
|
+
const log = (level, msg, meta) => logger[level](msg, meta);
|
|
371
426
|
log("info", `Starting stream processor: ${stream.description}`);
|
|
372
427
|
const checkpoint = await getCheckpoint(db, stream.name);
|
|
373
428
|
const startSlot = checkpoint ? checkpoint.slot : defaultStartSlot;
|
|
@@ -379,13 +434,6 @@ async function runEventStreamProcessor(stream, options, abortSignal) {
|
|
|
379
434
|
"info",
|
|
380
435
|
`Starting from slot ${startSlot}${checkpoint ? " (resuming)" : " (fresh start)"}`
|
|
381
436
|
);
|
|
382
|
-
const logger = logLevel === "debug" ? replay.createConsoleLogger(stream.name) : {
|
|
383
|
-
debug: () => {
|
|
384
|
-
},
|
|
385
|
-
info: (msg) => log("info", msg),
|
|
386
|
-
warn: (msg) => log("warn", msg),
|
|
387
|
-
error: (msg) => log("error", msg)
|
|
388
|
-
};
|
|
389
437
|
const replay$1 = replay.createEventReplay({
|
|
390
438
|
clientFactory,
|
|
391
439
|
startSlot,
|
|
@@ -394,7 +442,8 @@ async function runEventStreamProcessor(stream, options, abortSignal) {
|
|
|
394
442
|
pageSize,
|
|
395
443
|
filter: stream.getFilter(),
|
|
396
444
|
logger,
|
|
397
|
-
resubscribeOnEnd: true
|
|
445
|
+
resubscribeOnEnd: true,
|
|
446
|
+
signal: abortSignal
|
|
398
447
|
});
|
|
399
448
|
const batcher = new StreamBatcher();
|
|
400
449
|
const stats = {
|
|
@@ -612,20 +661,21 @@ function defineAccountStream(definition) {
|
|
|
612
661
|
api: definition.api
|
|
613
662
|
};
|
|
614
663
|
}
|
|
615
|
-
function shouldLog(level, minLevel) {
|
|
616
|
-
const levels = ["debug", "info", "warn", "error"];
|
|
617
|
-
return levels.indexOf(level) >= levels.indexOf(minLevel);
|
|
618
|
-
}
|
|
619
664
|
async function runAccountStreamProcessor(stream, options, abortSignal) {
|
|
620
|
-
const { clientFactory, db, logLevel = "info", validateParse = false, observer } = options;
|
|
665
|
+
const { clientFactory, db, logLevel = "info", logger: baseLogger, validateParse = false, observer } = options;
|
|
621
666
|
const checkpointName = `account:${stream.name}`;
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
667
|
+
const logger = createScopedLogger({
|
|
668
|
+
logger: baseLogger,
|
|
669
|
+
level: logLevel,
|
|
670
|
+
prefix: `account-stream:${stream.name}`,
|
|
671
|
+
bindings: {
|
|
672
|
+
component: "indexer-stream",
|
|
673
|
+
stream: stream.name,
|
|
674
|
+
kind: "account",
|
|
675
|
+
checkpoint_name: checkpointName
|
|
627
676
|
}
|
|
628
|
-
};
|
|
677
|
+
});
|
|
678
|
+
const log = (level, msg, meta) => logger[level](msg, meta);
|
|
629
679
|
const stats = {
|
|
630
680
|
accountsProcessed: 0,
|
|
631
681
|
accountsUpdated: 0,
|
|
@@ -644,18 +694,6 @@ async function runAccountStreamProcessor(stream, options, abortSignal) {
|
|
|
644
694
|
if (stream.expectedSize) {
|
|
645
695
|
log("info", `Expected data size: ${stream.expectedSize} bytes`);
|
|
646
696
|
}
|
|
647
|
-
const replayLogger = logLevel === "debug" ? {
|
|
648
|
-
debug: (msg) => log("debug", msg),
|
|
649
|
-
info: (msg) => log("info", msg),
|
|
650
|
-
warn: (msg) => log("warn", msg),
|
|
651
|
-
error: (msg) => log("error", msg)
|
|
652
|
-
} : {
|
|
653
|
-
debug: () => {
|
|
654
|
-
},
|
|
655
|
-
info: (msg) => log("info", msg),
|
|
656
|
-
warn: (msg) => log("warn", msg),
|
|
657
|
-
error: (msg) => log("error", msg)
|
|
658
|
-
};
|
|
659
697
|
let lastProcessedSlot = minUpdatedSlot ?? 0n;
|
|
660
698
|
try {
|
|
661
699
|
const replay$1 = replay.createAccountsByOwnerReplay({
|
|
@@ -664,7 +702,8 @@ async function runAccountStreamProcessor(stream, options, abortSignal) {
|
|
|
664
702
|
view: replay.AccountView.FULL,
|
|
665
703
|
dataSizes: stream.dataSizes ?? (stream.expectedSize ? [stream.expectedSize] : void 0),
|
|
666
704
|
minUpdatedSlot,
|
|
667
|
-
logger
|
|
705
|
+
logger,
|
|
706
|
+
signal: abortSignal,
|
|
668
707
|
onBackfillComplete: (highestSlot) => {
|
|
669
708
|
log(
|
|
670
709
|
"info",
|
|
@@ -870,11 +909,13 @@ function isRetryablePhase(phase) {
|
|
|
870
909
|
// src/runtime/indexer.ts
|
|
871
910
|
var Indexer = class {
|
|
872
911
|
config;
|
|
912
|
+
logger;
|
|
873
913
|
abortController = null;
|
|
874
914
|
running = false;
|
|
875
915
|
shutdownRequested = false;
|
|
876
916
|
startedAtMs = null;
|
|
877
917
|
streamStatuses = /* @__PURE__ */ new Map();
|
|
918
|
+
streamHealthStates = /* @__PURE__ */ new Map();
|
|
878
919
|
constructor(config) {
|
|
879
920
|
this.config = {
|
|
880
921
|
defaultStartSlot: 0n,
|
|
@@ -886,6 +927,12 @@ var Indexer = class {
|
|
|
886
927
|
streamStaleMs: 3e5,
|
|
887
928
|
...config
|
|
888
929
|
};
|
|
930
|
+
this.logger = createScopedLogger({
|
|
931
|
+
logger: this.config.logger,
|
|
932
|
+
level: this.config.logLevel,
|
|
933
|
+
prefix: "indexer",
|
|
934
|
+
bindings: { component: "indexer-runtime" }
|
|
935
|
+
});
|
|
889
936
|
this.initializeStreamStatuses();
|
|
890
937
|
}
|
|
891
938
|
/**
|
|
@@ -900,14 +947,14 @@ var Indexer = class {
|
|
|
900
947
|
} catch (err) {
|
|
901
948
|
const message = err instanceof Error ? err.cause instanceof Error ? err.cause.message : err.message : String(err);
|
|
902
949
|
if (message.includes("does not exist") || message.includes("relation")) {
|
|
903
|
-
|
|
904
|
-
`
|
|
905
|
-
|
|
950
|
+
this.logger.warn(
|
|
951
|
+
`Checkpoint table "indexer_checkpoints" not found.
|
|
952
|
+
Make sure to export checkpointTable from your Drizzle schema:
|
|
906
953
|
|
|
907
954
|
// db/schema.ts
|
|
908
955
|
export { checkpointTable } from "@thru/indexer";
|
|
909
956
|
|
|
910
|
-
|
|
957
|
+
Then run: pnpm drizzle-kit push (or generate + migrate)
|
|
911
958
|
`
|
|
912
959
|
);
|
|
913
960
|
}
|
|
@@ -944,15 +991,14 @@ var Indexer = class {
|
|
|
944
991
|
validateParse,
|
|
945
992
|
endpointLabel,
|
|
946
993
|
supervisorInitialBackoffMs = 1e3,
|
|
947
|
-
supervisorMaxBackoffMs = 3e4
|
|
994
|
+
supervisorMaxBackoffMs = 3e4,
|
|
995
|
+
logger
|
|
948
996
|
} = this.config;
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
`[indexer] Running ${accountStreams.length} account stream(s): ${accountStreams.map((s) => s.name).join(", ") || "none"}`
|
|
955
|
-
);
|
|
997
|
+
this.logger.info("Starting indexer", {
|
|
998
|
+
event: "indexer.started",
|
|
999
|
+
event_streams: eventStreams.map((stream) => stream.name),
|
|
1000
|
+
account_streams: accountStreams.map((stream) => stream.name)
|
|
1001
|
+
});
|
|
956
1002
|
try {
|
|
957
1003
|
const supervisorOptions = {
|
|
958
1004
|
endpointLabel,
|
|
@@ -967,6 +1013,7 @@ var Indexer = class {
|
|
|
967
1013
|
safetyMargin,
|
|
968
1014
|
pageSize,
|
|
969
1015
|
logLevel,
|
|
1016
|
+
logger,
|
|
970
1017
|
validateParse
|
|
971
1018
|
}, supervisorOptions)
|
|
972
1019
|
);
|
|
@@ -975,6 +1022,7 @@ var Indexer = class {
|
|
|
975
1022
|
clientFactory,
|
|
976
1023
|
db,
|
|
977
1024
|
logLevel,
|
|
1025
|
+
logger,
|
|
978
1026
|
validateParse
|
|
979
1027
|
}, supervisorOptions)
|
|
980
1028
|
);
|
|
@@ -983,7 +1031,9 @@ var Indexer = class {
|
|
|
983
1031
|
eventStreams: eventStreams.map((stream) => this.resultForStream(stream.name)),
|
|
984
1032
|
accountStreams: accountStreams.map((stream) => this.resultForStream(stream.name))
|
|
985
1033
|
};
|
|
986
|
-
|
|
1034
|
+
this.logger.info("All indexer streams stopped", {
|
|
1035
|
+
event: "indexer.stopped"
|
|
1036
|
+
});
|
|
987
1037
|
return result;
|
|
988
1038
|
} finally {
|
|
989
1039
|
this.running = false;
|
|
@@ -999,14 +1049,20 @@ var Indexer = class {
|
|
|
999
1049
|
*/
|
|
1000
1050
|
stop() {
|
|
1001
1051
|
if (!this.running || !this.abortController) {
|
|
1002
|
-
|
|
1052
|
+
this.logger.info("Indexer is not running", {
|
|
1053
|
+
event: "indexer.stop.noop"
|
|
1054
|
+
});
|
|
1003
1055
|
return;
|
|
1004
1056
|
}
|
|
1005
1057
|
if (this.shutdownRequested) {
|
|
1006
|
-
|
|
1058
|
+
this.logger.warn("Force shutting down indexer", {
|
|
1059
|
+
event: "indexer.force_shutdown"
|
|
1060
|
+
});
|
|
1007
1061
|
process.exit(1);
|
|
1008
1062
|
}
|
|
1009
|
-
|
|
1063
|
+
this.logger.info("Indexer shutdown requested", {
|
|
1064
|
+
event: "indexer.shutdown_requested"
|
|
1065
|
+
});
|
|
1010
1066
|
this.shutdownRequested = true;
|
|
1011
1067
|
this.abortController.abort();
|
|
1012
1068
|
}
|
|
@@ -1027,6 +1083,7 @@ var Indexer = class {
|
|
|
1027
1083
|
return stream;
|
|
1028
1084
|
});
|
|
1029
1085
|
const healthy = this.running && !this.shutdownRequested && streams.length > 0 && streams.every((stream) => stream.state === "running" && !stream.stale);
|
|
1086
|
+
this.emitHealthTransitions(streams, now);
|
|
1030
1087
|
return {
|
|
1031
1088
|
running: this.running,
|
|
1032
1089
|
shutdownRequested: this.shutdownRequested,
|
|
@@ -1038,6 +1095,7 @@ var Indexer = class {
|
|
|
1038
1095
|
}
|
|
1039
1096
|
initializeStreamStatuses() {
|
|
1040
1097
|
this.streamStatuses = /* @__PURE__ */ new Map();
|
|
1098
|
+
this.streamHealthStates = /* @__PURE__ */ new Map();
|
|
1041
1099
|
for (const stream of this.config.eventStreams ?? []) {
|
|
1042
1100
|
this.streamStatuses.set(this.statusKey("event", stream.name), this.createInitialStreamStatus("event", stream.name));
|
|
1043
1101
|
}
|
|
@@ -1079,6 +1137,84 @@ var Indexer = class {
|
|
|
1079
1137
|
status: "fulfilled"
|
|
1080
1138
|
};
|
|
1081
1139
|
}
|
|
1140
|
+
setStreamState(status, nextState, meta = {}) {
|
|
1141
|
+
const previousState = status.state;
|
|
1142
|
+
status.state = nextState;
|
|
1143
|
+
if (previousState === nextState) {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
this.logger.info("Indexer stream state changed", {
|
|
1147
|
+
event: "indexer.stream.state_changed",
|
|
1148
|
+
stream: status.name,
|
|
1149
|
+
kind: status.kind,
|
|
1150
|
+
previous_state: previousState,
|
|
1151
|
+
next_state: nextState,
|
|
1152
|
+
restart_count: status.restartCount,
|
|
1153
|
+
...meta
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
streamLogFields(stream) {
|
|
1157
|
+
return {
|
|
1158
|
+
stream: stream.name,
|
|
1159
|
+
kind: stream.kind,
|
|
1160
|
+
state: stream.state,
|
|
1161
|
+
stale: stream.stale,
|
|
1162
|
+
checkpoint_slot: stream.checkpointSlot,
|
|
1163
|
+
last_processed_slot: stream.lastProcessedSlot,
|
|
1164
|
+
last_event_at: stream.lastEventAt,
|
|
1165
|
+
restart_count: stream.restartCount,
|
|
1166
|
+
last_error_at: stream.lastErrorAt,
|
|
1167
|
+
last_error: stream.lastError
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
emitHealthTransitions(streams, nowMs) {
|
|
1171
|
+
if (!this.running || this.shutdownRequested) {
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
for (const stream of streams) {
|
|
1175
|
+
const key = this.statusKey(stream.kind, stream.name);
|
|
1176
|
+
const unhealthy = stream.state !== "running" || stream.stale;
|
|
1177
|
+
const previous = this.streamHealthStates.get(key);
|
|
1178
|
+
const initialStarting = !previous && stream.state === "starting" && stream.restartCount === 0 && !stream.lastError;
|
|
1179
|
+
if (initialStarting) {
|
|
1180
|
+
this.streamHealthStates.set(key, {
|
|
1181
|
+
unhealthy: false,
|
|
1182
|
+
unhealthySinceMs: null
|
|
1183
|
+
});
|
|
1184
|
+
continue;
|
|
1185
|
+
}
|
|
1186
|
+
if (unhealthy && previous?.unhealthy !== true) {
|
|
1187
|
+
this.streamHealthStates.set(key, {
|
|
1188
|
+
unhealthy: true,
|
|
1189
|
+
unhealthySinceMs: nowMs
|
|
1190
|
+
});
|
|
1191
|
+
this.logger.warn("Indexer stream unhealthy", {
|
|
1192
|
+
event: "indexer.stream.unhealthy",
|
|
1193
|
+
reason: stream.stale ? "stale" : "state",
|
|
1194
|
+
...this.streamLogFields(stream)
|
|
1195
|
+
});
|
|
1196
|
+
continue;
|
|
1197
|
+
}
|
|
1198
|
+
if (!unhealthy && previous?.unhealthy === true) {
|
|
1199
|
+
this.streamHealthStates.set(key, {
|
|
1200
|
+
unhealthy: false,
|
|
1201
|
+
unhealthySinceMs: null
|
|
1202
|
+
});
|
|
1203
|
+
this.logger.info("Indexer stream recovered", {
|
|
1204
|
+
event: "indexer.stream.recovered",
|
|
1205
|
+
unhealthy_duration_ms: previous.unhealthySinceMs === null ? null : nowMs - previous.unhealthySinceMs,
|
|
1206
|
+
...this.streamLogFields(stream)
|
|
1207
|
+
});
|
|
1208
|
+
continue;
|
|
1209
|
+
}
|
|
1210
|
+
if (!previous) {
|
|
1211
|
+
this.streamHealthStates.set(key, {
|
|
1212
|
+
unhealthy,
|
|
1213
|
+
unhealthySinceMs: unhealthy ? nowMs : null
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1082
1218
|
createObserver(kind, name, endpointLabel) {
|
|
1083
1219
|
const status = this.statusFor(kind, name);
|
|
1084
1220
|
let startSlot = null;
|
|
@@ -1087,7 +1223,10 @@ var Indexer = class {
|
|
|
1087
1223
|
onStart: (info) => {
|
|
1088
1224
|
startSlot = info.startSlot ?? null;
|
|
1089
1225
|
checkpointSlot = info.checkpointSlot ?? null;
|
|
1090
|
-
status
|
|
1226
|
+
this.setStreamState(status, "running", {
|
|
1227
|
+
start_slot: startSlot?.toString(),
|
|
1228
|
+
checkpoint_slot: checkpointSlot?.toString() ?? null
|
|
1229
|
+
});
|
|
1091
1230
|
status.checkpointSlot = checkpointSlot === null ? null : checkpointSlot.toString();
|
|
1092
1231
|
status.lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1093
1232
|
},
|
|
@@ -1159,23 +1298,26 @@ var Indexer = class {
|
|
|
1159
1298
|
const status = this.statusFor(kind, name);
|
|
1160
1299
|
while (!this.abortController?.signal.aborted) {
|
|
1161
1300
|
const observer = this.createObserver(kind, name, options.endpointLabel);
|
|
1162
|
-
status
|
|
1301
|
+
this.setStreamState(status, attempt === 0 ? "starting" : "retrying", {
|
|
1302
|
+
attempt
|
|
1303
|
+
});
|
|
1163
1304
|
status.lastStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1164
1305
|
try {
|
|
1165
1306
|
const summary = await runOnce(observer);
|
|
1166
1307
|
if (this.abortController?.signal.aborted) {
|
|
1167
|
-
status
|
|
1168
|
-
console.log(`[indexer] ${kind} stream "${name}" stopped: ${summary}`);
|
|
1308
|
+
this.setStreamState(status, "stopped", { summary });
|
|
1169
1309
|
return;
|
|
1170
1310
|
}
|
|
1171
1311
|
throw new Error(`${kind} stream "${name}" completed unexpectedly: ${summary}`);
|
|
1172
1312
|
} catch (error) {
|
|
1173
1313
|
if (this.abortController?.signal.aborted) {
|
|
1174
|
-
status
|
|
1314
|
+
this.setStreamState(status, "stopped");
|
|
1175
1315
|
return;
|
|
1176
1316
|
}
|
|
1177
1317
|
status.restartCount++;
|
|
1178
|
-
status
|
|
1318
|
+
this.setStreamState(status, "retrying", {
|
|
1319
|
+
restart_count: status.restartCount
|
|
1320
|
+
});
|
|
1179
1321
|
status.lastErrorAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1180
1322
|
if (!status.lastError || status.lastError.phase === "supervisor") {
|
|
1181
1323
|
status.lastError = normalizeIndexerError({
|
|
@@ -1187,15 +1329,21 @@ var Indexer = class {
|
|
|
1187
1329
|
});
|
|
1188
1330
|
}
|
|
1189
1331
|
const backoffMs = this.supervisorBackoffMs(attempt, options.initialBackoffMs, options.maxBackoffMs);
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1332
|
+
this.logger.warn("Indexer stream supervisor restarting", {
|
|
1333
|
+
event: "indexer.stream.supervisor_restart",
|
|
1334
|
+
stream: name,
|
|
1335
|
+
kind,
|
|
1336
|
+
backoff_ms: backoffMs,
|
|
1337
|
+
attempt: attempt + 1,
|
|
1338
|
+
restart_count: status.restartCount,
|
|
1339
|
+
error,
|
|
1340
|
+
last_error: status.lastError
|
|
1341
|
+
});
|
|
1194
1342
|
attempt++;
|
|
1195
1343
|
await this.delay(backoffMs, this.abortController.signal);
|
|
1196
1344
|
}
|
|
1197
1345
|
}
|
|
1198
|
-
status
|
|
1346
|
+
this.setStreamState(status, "stopped");
|
|
1199
1347
|
}
|
|
1200
1348
|
supervisorBackoffMs(attempt, initialMs, maxMs) {
|
|
1201
1349
|
const base = Math.min(maxMs, initialMs * Math.pow(2, attempt));
|