ponder 0.9.2 → 0.9.3
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/bin/ponder.js +1933 -1606
- package/dist/bin/ponder.js.map +1 -1
- package/dist/{chunk-IFTUFVCL.js → chunk-LHCA5XFV.js} +2 -5
- package/dist/chunk-LHCA5XFV.js.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/bin/commands/codegen.ts +8 -10
- package/src/bin/commands/dev.ts +30 -42
- package/src/bin/commands/list.ts +9 -14
- package/src/bin/commands/serve.ts +26 -39
- package/src/bin/commands/start.ts +29 -42
- package/src/bin/utils/{shutdown.ts → exit.ts} +23 -37
- package/src/bin/utils/run.ts +275 -175
- package/src/bin/utils/runServer.ts +1 -5
- package/src/build/index.ts +3 -8
- package/src/build/pre.ts +3 -0
- package/src/config/index.ts +5 -2
- package/src/database/index.ts +72 -72
- package/src/drizzle/kit/index.ts +3 -3
- package/src/indexing/index.ts +0 -4
- package/src/indexing/service.ts +31 -93
- package/src/indexing-store/historical.ts +2 -4
- package/src/internal/common.ts +2 -0
- package/src/internal/errors.ts +9 -9
- package/src/internal/logger.ts +1 -1
- package/src/internal/metrics.ts +75 -103
- package/src/internal/shutdown.ts +25 -0
- package/src/internal/telemetry.ts +16 -18
- package/src/internal/types.ts +9 -1
- package/src/server/index.ts +3 -5
- package/src/sync/events.ts +4 -4
- package/src/sync/filter.ts +1 -0
- package/src/sync/index.ts +1046 -805
- package/src/sync-historical/index.ts +0 -37
- package/src/sync-realtime/index.ts +48 -48
- package/src/sync-store/encoding.ts +5 -5
- package/src/sync-store/index.ts +5 -23
- package/src/ui/index.ts +2 -11
- package/src/utils/checkpoint.ts +17 -3
- package/src/utils/chunk.ts +7 -0
- package/src/utils/generators.ts +66 -0
- package/src/utils/mutex.ts +34 -0
- package/src/utils/partition.ts +41 -0
- package/src/utils/requestQueue.ts +19 -10
- package/src/utils/zipper.ts +80 -0
- package/dist/chunk-IFTUFVCL.js.map +0 -1
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
UniqueConstraintError,
|
|
14
14
|
} from "@/internal/errors.js";
|
|
15
15
|
import type { SchemaBuild } from "@/internal/types.js";
|
|
16
|
-
import { encodeCheckpoint, zeroCheckpoint } from "@/utils/checkpoint.js";
|
|
17
16
|
import { prettyPrint } from "@/utils/print.js";
|
|
18
17
|
import { createQueue } from "@ponder/common";
|
|
19
18
|
import {
|
|
@@ -146,12 +145,12 @@ export const createHistoricalIndexingStore = ({
|
|
|
146
145
|
common,
|
|
147
146
|
schemaBuild: { schema },
|
|
148
147
|
database,
|
|
149
|
-
|
|
148
|
+
isDatabaseEmpty,
|
|
150
149
|
}: {
|
|
151
150
|
common: Common;
|
|
152
151
|
schemaBuild: Pick<SchemaBuild, "schema">;
|
|
153
152
|
database: Database;
|
|
154
|
-
|
|
153
|
+
isDatabaseEmpty: boolean;
|
|
155
154
|
}): IndexingStore<"historical"> => {
|
|
156
155
|
// Operation queue to make sure all queries are run in order, circumventing race conditions
|
|
157
156
|
const queue = createQueue<unknown, () => Promise<unknown>>({
|
|
@@ -302,7 +301,6 @@ export const createHistoricalIndexingStore = ({
|
|
|
302
301
|
return size;
|
|
303
302
|
};
|
|
304
303
|
|
|
305
|
-
let isDatabaseEmpty = initialCheckpoint === encodeCheckpoint(zeroCheckpoint);
|
|
306
304
|
/** Estimated number of bytes used by cache. */
|
|
307
305
|
let cacheBytes = 0;
|
|
308
306
|
/** LRU counter. */
|
package/src/internal/common.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Logger } from "./logger.js";
|
|
2
2
|
import type { MetricsService } from "./metrics.js";
|
|
3
3
|
import type { Options } from "./options.js";
|
|
4
|
+
import type { Shutdown } from "./shutdown.js";
|
|
4
5
|
import type { Telemetry } from "./telemetry.js";
|
|
5
6
|
|
|
6
7
|
export type Common = {
|
|
@@ -8,4 +9,5 @@ export type Common = {
|
|
|
8
9
|
logger: Logger;
|
|
9
10
|
metrics: MetricsService;
|
|
10
11
|
telemetry: Telemetry;
|
|
12
|
+
shutdown: Shutdown;
|
|
11
13
|
};
|
package/src/internal/errors.ts
CHANGED
|
@@ -35,15 +35,6 @@ export class NonRetryableError extends BaseError {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export class IgnorableError extends BaseError {
|
|
39
|
-
override name = "IgnorableError";
|
|
40
|
-
|
|
41
|
-
constructor(message?: string | undefined) {
|
|
42
|
-
super(message);
|
|
43
|
-
Object.setPrototypeOf(this, IgnorableError.prototype);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
38
|
// Indexing store errors
|
|
48
39
|
|
|
49
40
|
export class StoreError extends NonRetryableError {
|
|
@@ -126,3 +117,12 @@ export class FlushError extends NonRetryableError {
|
|
|
126
117
|
Object.setPrototypeOf(this, FlushError.prototype);
|
|
127
118
|
}
|
|
128
119
|
}
|
|
120
|
+
|
|
121
|
+
export class ShutdownError extends NonRetryableError {
|
|
122
|
+
override name = "ShutdownError";
|
|
123
|
+
|
|
124
|
+
constructor(message?: string | undefined) {
|
|
125
|
+
super(message);
|
|
126
|
+
Object.setPrototypeOf(this, ShutdownError.prototype);
|
|
127
|
+
}
|
|
128
|
+
}
|
package/src/internal/logger.ts
CHANGED
package/src/internal/metrics.ts
CHANGED
|
@@ -17,14 +17,17 @@ const httpRequestSizeBytes = [
|
|
|
17
17
|
|
|
18
18
|
export class MetricsService {
|
|
19
19
|
registry: prometheus.Registry;
|
|
20
|
+
start_timestamp: number;
|
|
21
|
+
rps: { [network: string]: { count: number; timestamp: number }[] };
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
ponder_historical_total_indexing_seconds: prometheus.Gauge<"network">;
|
|
24
|
+
ponder_historical_cached_indexing_seconds: prometheus.Gauge<"network">;
|
|
25
|
+
ponder_historical_completed_indexing_seconds: prometheus.Gauge<"network">;
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
ponder_indexing_has_error: prometheus.Gauge
|
|
27
|
+
ponder_indexing_timestamp: prometheus.Gauge<"network">;
|
|
28
|
+
ponder_indexing_has_error: prometheus.Gauge<"network">;
|
|
27
29
|
|
|
30
|
+
ponder_indexing_completed_events: prometheus.Gauge<"event">;
|
|
28
31
|
ponder_indexing_function_duration: prometheus.Histogram<"event">;
|
|
29
32
|
ponder_indexing_abi_decoding_duration: prometheus.Histogram;
|
|
30
33
|
|
|
@@ -64,15 +67,25 @@ export class MetricsService {
|
|
|
64
67
|
|
|
65
68
|
constructor() {
|
|
66
69
|
this.registry = new prometheus.Registry();
|
|
70
|
+
this.start_timestamp = Date.now();
|
|
71
|
+
this.rps = {};
|
|
67
72
|
|
|
68
|
-
this.
|
|
69
|
-
name: "
|
|
73
|
+
this.ponder_historical_total_indexing_seconds = new prometheus.Gauge({
|
|
74
|
+
name: "ponder_historical_total_indexing_seconds",
|
|
70
75
|
help: "Total number of seconds that are required",
|
|
76
|
+
labelNames: ["network"] as const,
|
|
77
|
+
registers: [this.registry],
|
|
78
|
+
});
|
|
79
|
+
this.ponder_historical_cached_indexing_seconds = new prometheus.Gauge({
|
|
80
|
+
name: "ponder_historical_cached_indexing_seconds",
|
|
81
|
+
help: "Number of seconds that have been cached",
|
|
82
|
+
labelNames: ["network"] as const,
|
|
71
83
|
registers: [this.registry],
|
|
72
84
|
});
|
|
73
|
-
this.
|
|
74
|
-
name: "
|
|
85
|
+
this.ponder_historical_completed_indexing_seconds = new prometheus.Gauge({
|
|
86
|
+
name: "ponder_historical_completed_indexing_seconds",
|
|
75
87
|
help: "Number of seconds that have been completed",
|
|
88
|
+
labelNames: ["network"] as const,
|
|
76
89
|
registers: [this.registry],
|
|
77
90
|
});
|
|
78
91
|
this.ponder_indexing_completed_events = new prometheus.Gauge({
|
|
@@ -81,9 +94,10 @@ export class MetricsService {
|
|
|
81
94
|
labelNames: ["network", "event"] as const,
|
|
82
95
|
registers: [this.registry],
|
|
83
96
|
});
|
|
84
|
-
this.
|
|
85
|
-
name: "
|
|
97
|
+
this.ponder_indexing_timestamp = new prometheus.Gauge({
|
|
98
|
+
name: "ponder_indexing_timestamp",
|
|
86
99
|
help: "Timestamp through which all events have been completed",
|
|
100
|
+
labelNames: ["network"] as const,
|
|
87
101
|
registers: [this.registry],
|
|
88
102
|
});
|
|
89
103
|
this.ponder_indexing_has_error = new prometheus.Gauge({
|
|
@@ -245,10 +259,14 @@ export class MetricsService {
|
|
|
245
259
|
}
|
|
246
260
|
|
|
247
261
|
resetIndexingMetrics() {
|
|
248
|
-
this.
|
|
249
|
-
this.
|
|
262
|
+
this.start_timestamp = Date.now();
|
|
263
|
+
this.rps = {};
|
|
264
|
+
|
|
265
|
+
this.ponder_historical_total_indexing_seconds.reset();
|
|
266
|
+
this.ponder_historical_cached_indexing_seconds.reset();
|
|
267
|
+
this.ponder_historical_completed_indexing_seconds.reset();
|
|
250
268
|
this.ponder_indexing_completed_events.reset();
|
|
251
|
-
this.
|
|
269
|
+
this.ponder_indexing_timestamp.reset();
|
|
252
270
|
this.ponder_indexing_has_error.reset();
|
|
253
271
|
this.ponder_indexing_function_duration.reset();
|
|
254
272
|
this.ponder_indexing_abi_decoding_duration.reset();
|
|
@@ -284,8 +302,6 @@ export class MetricsService {
|
|
|
284
302
|
}
|
|
285
303
|
}
|
|
286
304
|
|
|
287
|
-
const rps: { [network: string]: { count: number; timestamp: number }[] } = {};
|
|
288
|
-
|
|
289
305
|
export async function getSyncProgress(metrics: MetricsService): Promise<
|
|
290
306
|
{
|
|
291
307
|
networkName: string;
|
|
@@ -338,14 +354,14 @@ export async function getSyncProgress(metrics: MetricsService): Promise<
|
|
|
338
354
|
}
|
|
339
355
|
|
|
340
356
|
for (const [networkName, count] of Object.entries(requestCount)) {
|
|
341
|
-
if (rps[networkName] === undefined) {
|
|
342
|
-
rps[networkName] = [{ count, timestamp: Date.now() }];
|
|
357
|
+
if (metrics.rps[networkName] === undefined) {
|
|
358
|
+
metrics.rps[networkName] = [{ count, timestamp: Date.now() }];
|
|
343
359
|
} else {
|
|
344
|
-
rps[networkName]!.push({ count, timestamp: Date.now() });
|
|
360
|
+
metrics.rps[networkName]!.push({ count, timestamp: Date.now() });
|
|
345
361
|
}
|
|
346
362
|
|
|
347
|
-
if (rps[networkName]!.length > 100) {
|
|
348
|
-
rps[networkName]!.shift();
|
|
363
|
+
if (metrics.rps[networkName]!.length > 100) {
|
|
364
|
+
metrics.rps[networkName]!.shift();
|
|
349
365
|
}
|
|
350
366
|
}
|
|
351
367
|
|
|
@@ -365,9 +381,9 @@ export async function getSyncProgress(metrics: MetricsService): Promise<
|
|
|
365
381
|
// The ETA is low quality if we've completed only one or two blocks.
|
|
366
382
|
const eta = completedBlocks >= 3 ? total - elapsed : undefined;
|
|
367
383
|
|
|
368
|
-
const _length = rps[labels.network!]!.length;
|
|
369
|
-
const _firstRps = rps[labels.network!]![0]!;
|
|
370
|
-
const _lastRps = rps[labels.network!]![_length - 1]!;
|
|
384
|
+
const _length = metrics.rps[labels.network!]!.length;
|
|
385
|
+
const _firstRps = metrics.rps[labels.network!]![0]!;
|
|
386
|
+
const _lastRps = metrics.rps[labels.network!]![_length - 1]!;
|
|
371
387
|
|
|
372
388
|
const requests = _lastRps.count - (_length > 1 ? _firstRps.count : 0);
|
|
373
389
|
const seconds =
|
|
@@ -389,16 +405,33 @@ export async function getIndexingProgress(metrics: MetricsService) {
|
|
|
389
405
|
.values[0]?.value;
|
|
390
406
|
const hasError = hasErrorMetric === 1;
|
|
391
407
|
|
|
392
|
-
const
|
|
393
|
-
|
|
408
|
+
const sum = (x: number[]) => x.reduce((a, b) => a + b, 0);
|
|
409
|
+
const max = (x: number[]) => x.reduce((a, b) => Math.max(a, b), 0);
|
|
410
|
+
|
|
411
|
+
const totalSeconds = await metrics.ponder_historical_total_indexing_seconds
|
|
412
|
+
.get()
|
|
413
|
+
.then(({ values }) => values.map(({ value }) => value))
|
|
414
|
+
.then(sum);
|
|
415
|
+
const cachedSeconds = await metrics.ponder_historical_cached_indexing_seconds
|
|
416
|
+
.get()
|
|
417
|
+
.then(({ values }) => values.map(({ value }) => value))
|
|
418
|
+
.then(sum);
|
|
394
419
|
const completedSeconds =
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
420
|
+
await metrics.ponder_historical_completed_indexing_seconds
|
|
421
|
+
.get()
|
|
422
|
+
.then(({ values }) => values.map(({ value }) => value))
|
|
423
|
+
.then(sum);
|
|
424
|
+
const timestamp = await metrics.ponder_indexing_timestamp
|
|
425
|
+
.get()
|
|
426
|
+
.then(({ values }) => values.map(({ value }) => value))
|
|
427
|
+
.then(max);
|
|
400
428
|
|
|
401
|
-
const progress =
|
|
429
|
+
const progress =
|
|
430
|
+
timestamp === 0
|
|
431
|
+
? 0
|
|
432
|
+
: totalSeconds === 0
|
|
433
|
+
? 1
|
|
434
|
+
: (completedSeconds + cachedSeconds) / totalSeconds;
|
|
402
435
|
|
|
403
436
|
const indexingCompletedEventsMetric = (
|
|
404
437
|
await metrics.ponder_indexing_completed_events.get()
|
|
@@ -433,10 +466,10 @@ export async function getIndexingProgress(metrics: MetricsService) {
|
|
|
433
466
|
return {
|
|
434
467
|
hasError,
|
|
435
468
|
overall: {
|
|
436
|
-
completedSeconds,
|
|
437
469
|
totalSeconds,
|
|
470
|
+
cachedSeconds,
|
|
471
|
+
completedSeconds,
|
|
438
472
|
progress,
|
|
439
|
-
completedToTimestamp,
|
|
440
473
|
totalEvents,
|
|
441
474
|
},
|
|
442
475
|
events,
|
|
@@ -444,86 +477,25 @@ export async function getIndexingProgress(metrics: MetricsService) {
|
|
|
444
477
|
}
|
|
445
478
|
|
|
446
479
|
export async function getAppProgress(metrics: MetricsService): Promise<{
|
|
447
|
-
mode: "historical" | "realtime" |
|
|
480
|
+
mode: "historical" | "realtime" | undefined;
|
|
448
481
|
progress: number;
|
|
449
482
|
eta: number | undefined;
|
|
450
483
|
}> {
|
|
451
|
-
const sync = await getSyncProgress(metrics);
|
|
452
484
|
const indexing = await getIndexingProgress(metrics);
|
|
453
|
-
const decodingSum = await metrics.ponder_indexing_abi_decoding_duration
|
|
454
|
-
.get()
|
|
455
|
-
.then(
|
|
456
|
-
(m) =>
|
|
457
|
-
m.values.find(
|
|
458
|
-
(v) => v.metricName === "ponder_indexing_abi_decoding_duration_sum",
|
|
459
|
-
)?.value,
|
|
460
|
-
);
|
|
461
|
-
const getEventsSum = await metrics.ponder_database_method_duration
|
|
462
|
-
.get()
|
|
463
|
-
.then(
|
|
464
|
-
(m) =>
|
|
465
|
-
m.values.find(
|
|
466
|
-
(v) =>
|
|
467
|
-
v.labels.method === "getEvents" &&
|
|
468
|
-
v.metricName === "ponder_database_method_duration_sum",
|
|
469
|
-
)?.value,
|
|
470
|
-
);
|
|
471
|
-
const indexingSum = indexing.events.reduce(
|
|
472
|
-
(acc, cur) => acc + cur.averageDuration * cur.count,
|
|
473
|
-
0,
|
|
474
|
-
);
|
|
475
|
-
|
|
476
|
-
let maxSync: (typeof sync)[number] | undefined;
|
|
477
|
-
for (const networkSync of sync) {
|
|
478
|
-
if (
|
|
479
|
-
maxSync === undefined ||
|
|
480
|
-
maxSync.eta === undefined ||
|
|
481
|
-
(networkSync.eta && networkSync.eta > maxSync.eta)
|
|
482
|
-
) {
|
|
483
|
-
maxSync = networkSync;
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
485
|
|
|
487
486
|
const remainingSeconds =
|
|
488
|
-
indexing.overall.totalSeconds -
|
|
487
|
+
indexing.overall.totalSeconds -
|
|
488
|
+
(indexing.overall.completedSeconds + indexing.overall.cachedSeconds);
|
|
489
|
+
const elapsedSeconds = (Date.now() - metrics.start_timestamp) / 1_000;
|
|
489
490
|
|
|
490
|
-
const
|
|
491
|
+
const eta =
|
|
491
492
|
indexing.overall.completedSeconds === 0
|
|
492
|
-
? undefined
|
|
493
|
-
: (((decodingSum ?? 0) + (getEventsSum ?? 0) + indexingSum) *
|
|
494
|
-
remainingSeconds) /
|
|
495
|
-
indexing.overall.completedSeconds;
|
|
496
|
-
|
|
497
|
-
const eta = sync.every((n) => n.progress === 1)
|
|
498
|
-
? indexingEta
|
|
499
|
-
: maxSync?.eta === undefined && indexingEta === undefined
|
|
500
|
-
? undefined
|
|
501
|
-
: maxSync?.eta === undefined && maxSync?.progress !== undefined
|
|
502
|
-
? undefined
|
|
503
|
-
: Math.max(maxSync?.eta ?? 0, indexingEta ?? 0);
|
|
504
|
-
|
|
505
|
-
// Edge case: If all matched events occurred in the same unix timestamp (second), progress will
|
|
506
|
-
// be zero, even though indexing is complete. When this happens, totalEvents will be non-zero.
|
|
507
|
-
const indexingProgress =
|
|
508
|
-
indexing.overall.progress === 0 && indexing.overall.totalEvents > 0
|
|
509
|
-
? 1
|
|
510
|
-
: indexing.overall.progress;
|
|
511
|
-
|
|
512
|
-
const progress = sync.every((n) => n.progress === 1)
|
|
513
|
-
? indexingProgress
|
|
514
|
-
: maxSync?.progress === undefined
|
|
515
493
|
? 0
|
|
516
|
-
:
|
|
494
|
+
: (elapsedSeconds / indexing.overall.completedSeconds) * remainingSeconds;
|
|
517
495
|
|
|
518
496
|
return {
|
|
519
|
-
mode:
|
|
520
|
-
|
|
521
|
-
: sync.every((n) => n.status === "complete")
|
|
522
|
-
? "complete"
|
|
523
|
-
: sync.length === 0
|
|
524
|
-
? undefined
|
|
525
|
-
: "historical",
|
|
526
|
-
progress,
|
|
497
|
+
mode: indexing.overall.progress === 1 ? "realtime" : "historical",
|
|
498
|
+
progress: indexing.overall.progress,
|
|
527
499
|
eta,
|
|
528
500
|
};
|
|
529
501
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type Shutdown = {
|
|
2
|
+
add: (callback: () => unknown | Promise<unknown>) => void;
|
|
3
|
+
kill: () => Promise<void>;
|
|
4
|
+
isKilled: boolean;
|
|
5
|
+
abortController: AbortController;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const createShutdown = (): Shutdown => {
|
|
9
|
+
const abortController = new AbortController();
|
|
10
|
+
const callbacks: (() => unknown | Promise<unknown>)[] = [];
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
add: (callback) => {
|
|
14
|
+
callbacks.push(callback);
|
|
15
|
+
},
|
|
16
|
+
kill: async () => {
|
|
17
|
+
abortController.abort();
|
|
18
|
+
await Promise.all(callbacks.map((callback) => callback()));
|
|
19
|
+
},
|
|
20
|
+
get isKilled() {
|
|
21
|
+
return abortController.signal.aborted;
|
|
22
|
+
},
|
|
23
|
+
abortController,
|
|
24
|
+
};
|
|
25
|
+
};
|
|
@@ -6,11 +6,12 @@ import path from "node:path";
|
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
7
|
import type { Options } from "@/internal/options.js";
|
|
8
8
|
import { startClock } from "@/utils/timer.js";
|
|
9
|
-
import { wait } from "@/utils/wait.js";
|
|
10
9
|
import { createQueue } from "@ponder/common";
|
|
11
10
|
import Conf from "conf";
|
|
12
11
|
import { type PM, detect, getNpmVersion } from "detect-package-manager";
|
|
12
|
+
import { ShutdownError } from "./errors.js";
|
|
13
13
|
import type { Logger } from "./logger.js";
|
|
14
|
+
import type { Shutdown } from "./shutdown.js";
|
|
14
15
|
import type { IndexingBuild } from "./types.js";
|
|
15
16
|
import type { PreBuild, SchemaBuild } from "./types.js";
|
|
16
17
|
|
|
@@ -65,12 +66,12 @@ export type Telemetry = ReturnType<typeof createTelemetry>;
|
|
|
65
66
|
export function createTelemetry({
|
|
66
67
|
options,
|
|
67
68
|
logger,
|
|
68
|
-
|
|
69
|
+
shutdown,
|
|
70
|
+
}: { options: Options; logger: Logger; shutdown: Shutdown }) {
|
|
69
71
|
if (options.telemetryDisabled) {
|
|
70
72
|
return {
|
|
71
73
|
record: (_event: TelemetryEvent) => {},
|
|
72
74
|
flush: async () => {},
|
|
73
|
-
kill: async () => {},
|
|
74
75
|
};
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -156,13 +157,12 @@ export function createTelemetry({
|
|
|
156
157
|
let context: Awaited<ReturnType<typeof buildContext>> | undefined = undefined;
|
|
157
158
|
const contextPromise = buildContext();
|
|
158
159
|
|
|
159
|
-
const controller = new AbortController();
|
|
160
|
-
let isKilled = false;
|
|
161
|
-
|
|
162
160
|
const queue = createQueue({
|
|
163
161
|
initialStart: true,
|
|
164
162
|
concurrency: 10,
|
|
165
163
|
worker: async (event: TelemetryEvent) => {
|
|
164
|
+
if (shutdown.isKilled) return;
|
|
165
|
+
|
|
166
166
|
const endClock = startClock();
|
|
167
167
|
try {
|
|
168
168
|
if (context === undefined) context = await contextPromise;
|
|
@@ -182,7 +182,6 @@ export function createTelemetry({
|
|
|
182
182
|
method: "POST",
|
|
183
183
|
headers: { "Content-Type": "application/json" },
|
|
184
184
|
body,
|
|
185
|
-
signal: controller.signal,
|
|
186
185
|
});
|
|
187
186
|
logger.trace({
|
|
188
187
|
service: "telemetry",
|
|
@@ -190,6 +189,11 @@ export function createTelemetry({
|
|
|
190
189
|
});
|
|
191
190
|
} catch (error_) {
|
|
192
191
|
const error = error_ as Error;
|
|
192
|
+
|
|
193
|
+
if (shutdown.isKilled) {
|
|
194
|
+
throw new ShutdownError();
|
|
195
|
+
}
|
|
196
|
+
|
|
193
197
|
logger.trace({
|
|
194
198
|
service: "telemetry",
|
|
195
199
|
msg: `Failed to send '${event.name}' event after ${endClock()}ms`,
|
|
@@ -200,7 +204,6 @@ export function createTelemetry({
|
|
|
200
204
|
});
|
|
201
205
|
|
|
202
206
|
const record = (event: TelemetryEvent) => {
|
|
203
|
-
if (isKilled) return;
|
|
204
207
|
queue.add(event);
|
|
205
208
|
};
|
|
206
209
|
|
|
@@ -211,21 +214,16 @@ export function createTelemetry({
|
|
|
211
214
|
});
|
|
212
215
|
}, HEARTBEAT_INTERVAL_MS);
|
|
213
216
|
|
|
217
|
+
shutdown.add(() => {
|
|
218
|
+
clearInterval(heartbeatInterval);
|
|
219
|
+
});
|
|
220
|
+
|
|
214
221
|
// Note that this method is only used for testing.
|
|
215
222
|
const flush = async () => {
|
|
216
223
|
await queue.onIdle();
|
|
217
224
|
};
|
|
218
225
|
|
|
219
|
-
|
|
220
|
-
clearInterval(heartbeatInterval);
|
|
221
|
-
isKilled = true;
|
|
222
|
-
// If there are any events in the queue that have not started, drop them.
|
|
223
|
-
queue.clear();
|
|
224
|
-
// Wait at most 1 second for any in-flight events to complete.
|
|
225
|
-
await Promise.race([queue.onIdle(), wait(1_000)]);
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
return { record, flush, kill };
|
|
226
|
+
return { record, flush };
|
|
229
227
|
}
|
|
230
228
|
|
|
231
229
|
async function getPackageManager() {
|
package/src/internal/types.ts
CHANGED
|
@@ -284,8 +284,8 @@ export type BlockMetadata = {
|
|
|
284
284
|
export type Network = {
|
|
285
285
|
name: string;
|
|
286
286
|
chainId: number;
|
|
287
|
-
chain: Chain;
|
|
288
287
|
transport: ReturnType<Transport>;
|
|
288
|
+
chain: Chain;
|
|
289
289
|
pollingInterval: number;
|
|
290
290
|
maxRequestsPerSecond: number;
|
|
291
291
|
finalityBlockCount: number;
|
|
@@ -306,6 +306,8 @@ export type NamespaceBuild = string;
|
|
|
306
306
|
export type PreBuild = {
|
|
307
307
|
/** Database type and configuration */
|
|
308
308
|
databaseConfig: DatabaseConfig;
|
|
309
|
+
/** Ordering of events */
|
|
310
|
+
ordering: "omnichain" | "multichain";
|
|
309
311
|
};
|
|
310
312
|
|
|
311
313
|
export type SchemaBuild = {
|
|
@@ -344,6 +346,12 @@ export type Status = {
|
|
|
344
346
|
};
|
|
345
347
|
};
|
|
346
348
|
|
|
349
|
+
// Seconds
|
|
350
|
+
|
|
351
|
+
export type Seconds = {
|
|
352
|
+
[network: string]: { start: number; end: number; cached: number };
|
|
353
|
+
};
|
|
354
|
+
|
|
347
355
|
// Events
|
|
348
356
|
|
|
349
357
|
export type RawEvent = {
|
package/src/server/index.ts
CHANGED
|
@@ -13,7 +13,6 @@ import { onError } from "./error.js";
|
|
|
13
13
|
|
|
14
14
|
export type Server = {
|
|
15
15
|
hono: Hono;
|
|
16
|
-
kill: () => Promise<void>;
|
|
17
16
|
};
|
|
18
17
|
|
|
19
18
|
export async function createServer({
|
|
@@ -145,8 +144,7 @@ export async function createServer({
|
|
|
145
144
|
gracefulTerminationTimeout: 1000,
|
|
146
145
|
});
|
|
147
146
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
};
|
|
147
|
+
common.shutdown.add(() => terminator.terminate());
|
|
148
|
+
|
|
149
|
+
return { hono };
|
|
152
150
|
}
|
package/src/sync/events.ts
CHANGED
|
@@ -23,9 +23,9 @@ import type {
|
|
|
23
23
|
} from "@/types/sync.js";
|
|
24
24
|
import {
|
|
25
25
|
EVENT_TYPES,
|
|
26
|
+
MAX_CHECKPOINT,
|
|
27
|
+
ZERO_CHECKPOINT,
|
|
26
28
|
encodeCheckpoint,
|
|
27
|
-
maxCheckpoint,
|
|
28
|
-
zeroCheckpoint,
|
|
29
29
|
} from "@/utils/checkpoint.js";
|
|
30
30
|
import { never } from "@/utils/never.js";
|
|
31
31
|
import { startClock } from "@/utils/timer.js";
|
|
@@ -329,9 +329,9 @@ export const buildEvents = ({
|
|
|
329
329
|
blockTimestamp: hexToNumber(block.timestamp),
|
|
330
330
|
chainId: BigInt(filter.chainId),
|
|
331
331
|
blockNumber: hexToBigInt(block.number),
|
|
332
|
-
transactionIndex:
|
|
332
|
+
transactionIndex: MAX_CHECKPOINT.transactionIndex,
|
|
333
333
|
eventType: EVENT_TYPES.blocks,
|
|
334
|
-
eventIndex:
|
|
334
|
+
eventIndex: ZERO_CHECKPOINT.eventIndex,
|
|
335
335
|
}),
|
|
336
336
|
block: convertBlock(block),
|
|
337
337
|
log: undefined,
|
package/src/sync/filter.ts
CHANGED