@apibara/plugin-mongo 2.1.0-beta.2 → 2.1.0-beta.20
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 +66 -24
- package/dist/index.mjs +67 -25
- package/package.json +3 -3
- package/src/index.ts +39 -4
- package/src/mongo.ts +17 -0
- package/src/persistence.ts +28 -8
- package/src/utils.ts +10 -5
package/dist/index.cjs
CHANGED
|
@@ -39,17 +39,42 @@ async function finalize(db, session, cursor, collections) {
|
|
|
39
39
|
);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
async function cleanupStorage(db, session, collections) {
|
|
43
|
+
for (const collection of collections) {
|
|
44
|
+
try {
|
|
45
|
+
await db.collection(collection).deleteMany({}, { session });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new Error(`Failed to clean up collection ${collection}`, {
|
|
48
|
+
cause: error
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class MongoStorageError extends Error {
|
|
55
|
+
constructor(message, options) {
|
|
56
|
+
super(message, options);
|
|
57
|
+
this.name = "MongoStorageError";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function withTransaction(client, cb) {
|
|
61
|
+
return await client.withSession(async (session) => {
|
|
62
|
+
return await session.withTransaction(
|
|
63
|
+
async (session2) => {
|
|
64
|
+
return await cb(session2);
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
retryWrites: false
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
42
72
|
|
|
43
73
|
const checkpointCollectionName = "checkpoints";
|
|
44
74
|
const filterCollectionName = "filters";
|
|
45
75
|
async function initializePersistentState(db, session) {
|
|
46
|
-
const checkpoint =
|
|
47
|
-
|
|
48
|
-
{ session }
|
|
49
|
-
);
|
|
50
|
-
const filter = await db.createCollection(filterCollectionName, {
|
|
51
|
-
session
|
|
52
|
-
});
|
|
76
|
+
const checkpoint = db.collection(checkpointCollectionName);
|
|
77
|
+
const filter = db.collection(filterCollectionName);
|
|
53
78
|
await checkpoint.createIndex({ id: 1 }, { session });
|
|
54
79
|
await filter.createIndex({ id: 1, fromBlock: 1 }, { session });
|
|
55
80
|
}
|
|
@@ -61,7 +86,7 @@ async function persistState(props) {
|
|
|
61
86
|
{
|
|
62
87
|
$set: {
|
|
63
88
|
orderKey: Number(endCursor.orderKey),
|
|
64
|
-
uniqueKey: endCursor.uniqueKey
|
|
89
|
+
uniqueKey: endCursor.uniqueKey ? endCursor.uniqueKey : null
|
|
65
90
|
}
|
|
66
91
|
},
|
|
67
92
|
{ upsert: true, session }
|
|
@@ -134,6 +159,17 @@ async function finalizeState(props) {
|
|
|
134
159
|
{ session }
|
|
135
160
|
);
|
|
136
161
|
}
|
|
162
|
+
async function resetPersistence(props) {
|
|
163
|
+
const { db, session, indexerId } = props;
|
|
164
|
+
try {
|
|
165
|
+
await db.collection(checkpointCollectionName).deleteMany({ id: indexerId }, { session });
|
|
166
|
+
await db.collection(filterCollectionName).deleteMany({ id: indexerId }, { session });
|
|
167
|
+
} catch (error) {
|
|
168
|
+
throw new MongoStorageError("Failed to reset persistence state", {
|
|
169
|
+
cause: error
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
137
173
|
|
|
138
174
|
class MongoStorage {
|
|
139
175
|
constructor(db, session, endCursor) {
|
|
@@ -305,20 +341,6 @@ class MongoCollection {
|
|
|
305
341
|
}
|
|
306
342
|
}
|
|
307
343
|
|
|
308
|
-
class MongoStorageError extends Error {
|
|
309
|
-
constructor(message) {
|
|
310
|
-
super(message);
|
|
311
|
-
this.name = "MongoStorageError";
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
async function withTransaction(client, cb) {
|
|
315
|
-
return await client.withSession(async (session) => {
|
|
316
|
-
return await session.withTransaction(async (session2) => {
|
|
317
|
-
return await cb(session2);
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
|
|
322
344
|
const MONGO_PROPERTY = "_mongo";
|
|
323
345
|
function useMongoStorage() {
|
|
324
346
|
const context = indexer.useIndexerContext();
|
|
@@ -339,9 +361,25 @@ function mongoStorage({
|
|
|
339
361
|
}) {
|
|
340
362
|
return plugins.defineIndexerPlugin((indexer) => {
|
|
341
363
|
let indexerId = "";
|
|
364
|
+
const alwaysReindex = process.env["APIBARA_ALWAYS_REINDEX"] === "true";
|
|
365
|
+
let prevFinality;
|
|
342
366
|
indexer.hooks.hook("run:before", async () => {
|
|
343
367
|
const { indexerName } = plugins$1.useInternalContext();
|
|
344
368
|
indexerId = internal.generateIndexerId(indexerName, identifier);
|
|
369
|
+
const logger = plugins.useLogger();
|
|
370
|
+
if (alwaysReindex) {
|
|
371
|
+
logger.warn(
|
|
372
|
+
`Reindexing: Deleting all data from collections - ${collections.join(", ")}`
|
|
373
|
+
);
|
|
374
|
+
await withTransaction(client, async (session) => {
|
|
375
|
+
const db = client.db(dbName, dbOptions);
|
|
376
|
+
await cleanupStorage(db, session, collections);
|
|
377
|
+
if (enablePersistence) {
|
|
378
|
+
await resetPersistence({ db, session, indexerId });
|
|
379
|
+
}
|
|
380
|
+
logger.success("All data has been cleaned up for reindexing");
|
|
381
|
+
});
|
|
382
|
+
}
|
|
345
383
|
await withTransaction(client, async (session) => {
|
|
346
384
|
const db = client.db(dbName, dbOptions);
|
|
347
385
|
if (enablePersistence) {
|
|
@@ -426,16 +464,19 @@ function mongoStorage({
|
|
|
426
464
|
});
|
|
427
465
|
indexer.hooks.hook("handler:middleware", async ({ use }) => {
|
|
428
466
|
use(async (context, next) => {
|
|
429
|
-
const { endCursor } = context;
|
|
467
|
+
const { endCursor, finality, cursor } = context;
|
|
430
468
|
if (!endCursor) {
|
|
431
469
|
throw new MongoStorageError("end cursor is undefined");
|
|
432
470
|
}
|
|
433
471
|
await withTransaction(client, async (session) => {
|
|
434
472
|
const db = client.db(dbName, dbOptions);
|
|
435
473
|
context[MONGO_PROPERTY] = new MongoStorage(db, session, endCursor);
|
|
474
|
+
if (prevFinality === "pending") {
|
|
475
|
+
await invalidate(db, session, cursor, collections);
|
|
476
|
+
}
|
|
436
477
|
await next();
|
|
437
478
|
delete context[MONGO_PROPERTY];
|
|
438
|
-
if (enablePersistence) {
|
|
479
|
+
if (enablePersistence && finality !== "pending") {
|
|
439
480
|
await persistState({
|
|
440
481
|
db,
|
|
441
482
|
endCursor,
|
|
@@ -443,6 +484,7 @@ function mongoStorage({
|
|
|
443
484
|
indexerId
|
|
444
485
|
});
|
|
445
486
|
}
|
|
487
|
+
prevFinality = finality;
|
|
446
488
|
});
|
|
447
489
|
});
|
|
448
490
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useIndexerContext } from '@apibara/indexer';
|
|
2
|
-
import { defineIndexerPlugin } from '@apibara/indexer/plugins';
|
|
2
|
+
import { defineIndexerPlugin, useLogger } from '@apibara/indexer/plugins';
|
|
3
3
|
import { generateIndexerId } from '@apibara/indexer/internal';
|
|
4
4
|
import { useInternalContext } from '@apibara/indexer/internal/plugins';
|
|
5
5
|
import { normalizeCursor } from '@apibara/protocol';
|
|
@@ -37,17 +37,42 @@ async function finalize(db, session, cursor, collections) {
|
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
+
async function cleanupStorage(db, session, collections) {
|
|
41
|
+
for (const collection of collections) {
|
|
42
|
+
try {
|
|
43
|
+
await db.collection(collection).deleteMany({}, { session });
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw new Error(`Failed to clean up collection ${collection}`, {
|
|
46
|
+
cause: error
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
class MongoStorageError extends Error {
|
|
53
|
+
constructor(message, options) {
|
|
54
|
+
super(message, options);
|
|
55
|
+
this.name = "MongoStorageError";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function withTransaction(client, cb) {
|
|
59
|
+
return await client.withSession(async (session) => {
|
|
60
|
+
return await session.withTransaction(
|
|
61
|
+
async (session2) => {
|
|
62
|
+
return await cb(session2);
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
retryWrites: false
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
40
70
|
|
|
41
71
|
const checkpointCollectionName = "checkpoints";
|
|
42
72
|
const filterCollectionName = "filters";
|
|
43
73
|
async function initializePersistentState(db, session) {
|
|
44
|
-
const checkpoint =
|
|
45
|
-
|
|
46
|
-
{ session }
|
|
47
|
-
);
|
|
48
|
-
const filter = await db.createCollection(filterCollectionName, {
|
|
49
|
-
session
|
|
50
|
-
});
|
|
74
|
+
const checkpoint = db.collection(checkpointCollectionName);
|
|
75
|
+
const filter = db.collection(filterCollectionName);
|
|
51
76
|
await checkpoint.createIndex({ id: 1 }, { session });
|
|
52
77
|
await filter.createIndex({ id: 1, fromBlock: 1 }, { session });
|
|
53
78
|
}
|
|
@@ -59,7 +84,7 @@ async function persistState(props) {
|
|
|
59
84
|
{
|
|
60
85
|
$set: {
|
|
61
86
|
orderKey: Number(endCursor.orderKey),
|
|
62
|
-
uniqueKey: endCursor.uniqueKey
|
|
87
|
+
uniqueKey: endCursor.uniqueKey ? endCursor.uniqueKey : null
|
|
63
88
|
}
|
|
64
89
|
},
|
|
65
90
|
{ upsert: true, session }
|
|
@@ -132,6 +157,17 @@ async function finalizeState(props) {
|
|
|
132
157
|
{ session }
|
|
133
158
|
);
|
|
134
159
|
}
|
|
160
|
+
async function resetPersistence(props) {
|
|
161
|
+
const { db, session, indexerId } = props;
|
|
162
|
+
try {
|
|
163
|
+
await db.collection(checkpointCollectionName).deleteMany({ id: indexerId }, { session });
|
|
164
|
+
await db.collection(filterCollectionName).deleteMany({ id: indexerId }, { session });
|
|
165
|
+
} catch (error) {
|
|
166
|
+
throw new MongoStorageError("Failed to reset persistence state", {
|
|
167
|
+
cause: error
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
135
171
|
|
|
136
172
|
class MongoStorage {
|
|
137
173
|
constructor(db, session, endCursor) {
|
|
@@ -303,20 +339,6 @@ class MongoCollection {
|
|
|
303
339
|
}
|
|
304
340
|
}
|
|
305
341
|
|
|
306
|
-
class MongoStorageError extends Error {
|
|
307
|
-
constructor(message) {
|
|
308
|
-
super(message);
|
|
309
|
-
this.name = "MongoStorageError";
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
async function withTransaction(client, cb) {
|
|
313
|
-
return await client.withSession(async (session) => {
|
|
314
|
-
return await session.withTransaction(async (session2) => {
|
|
315
|
-
return await cb(session2);
|
|
316
|
-
});
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
|
|
320
342
|
const MONGO_PROPERTY = "_mongo";
|
|
321
343
|
function useMongoStorage() {
|
|
322
344
|
const context = useIndexerContext();
|
|
@@ -337,9 +359,25 @@ function mongoStorage({
|
|
|
337
359
|
}) {
|
|
338
360
|
return defineIndexerPlugin((indexer) => {
|
|
339
361
|
let indexerId = "";
|
|
362
|
+
const alwaysReindex = process.env["APIBARA_ALWAYS_REINDEX"] === "true";
|
|
363
|
+
let prevFinality;
|
|
340
364
|
indexer.hooks.hook("run:before", async () => {
|
|
341
365
|
const { indexerName } = useInternalContext();
|
|
342
366
|
indexerId = generateIndexerId(indexerName, identifier);
|
|
367
|
+
const logger = useLogger();
|
|
368
|
+
if (alwaysReindex) {
|
|
369
|
+
logger.warn(
|
|
370
|
+
`Reindexing: Deleting all data from collections - ${collections.join(", ")}`
|
|
371
|
+
);
|
|
372
|
+
await withTransaction(client, async (session) => {
|
|
373
|
+
const db = client.db(dbName, dbOptions);
|
|
374
|
+
await cleanupStorage(db, session, collections);
|
|
375
|
+
if (enablePersistence) {
|
|
376
|
+
await resetPersistence({ db, session, indexerId });
|
|
377
|
+
}
|
|
378
|
+
logger.success("All data has been cleaned up for reindexing");
|
|
379
|
+
});
|
|
380
|
+
}
|
|
343
381
|
await withTransaction(client, async (session) => {
|
|
344
382
|
const db = client.db(dbName, dbOptions);
|
|
345
383
|
if (enablePersistence) {
|
|
@@ -424,16 +462,19 @@ function mongoStorage({
|
|
|
424
462
|
});
|
|
425
463
|
indexer.hooks.hook("handler:middleware", async ({ use }) => {
|
|
426
464
|
use(async (context, next) => {
|
|
427
|
-
const { endCursor } = context;
|
|
465
|
+
const { endCursor, finality, cursor } = context;
|
|
428
466
|
if (!endCursor) {
|
|
429
467
|
throw new MongoStorageError("end cursor is undefined");
|
|
430
468
|
}
|
|
431
469
|
await withTransaction(client, async (session) => {
|
|
432
470
|
const db = client.db(dbName, dbOptions);
|
|
433
471
|
context[MONGO_PROPERTY] = new MongoStorage(db, session, endCursor);
|
|
472
|
+
if (prevFinality === "pending") {
|
|
473
|
+
await invalidate(db, session, cursor, collections);
|
|
474
|
+
}
|
|
434
475
|
await next();
|
|
435
476
|
delete context[MONGO_PROPERTY];
|
|
436
|
-
if (enablePersistence) {
|
|
477
|
+
if (enablePersistence && finality !== "pending") {
|
|
437
478
|
await persistState({
|
|
438
479
|
db,
|
|
439
480
|
endCursor,
|
|
@@ -441,6 +482,7 @@ function mongoStorage({
|
|
|
441
482
|
indexerId
|
|
442
483
|
});
|
|
443
484
|
}
|
|
485
|
+
prevFinality = finality;
|
|
444
486
|
});
|
|
445
487
|
});
|
|
446
488
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apibara/plugin-mongo",
|
|
3
|
-
"version": "2.1.0-beta.
|
|
3
|
+
"version": "2.1.0-beta.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"mongodb": "^6.12.0"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@apibara/indexer": "2.1.0-beta.
|
|
39
|
-
"@apibara/protocol": "2.1.0-beta.
|
|
38
|
+
"@apibara/indexer": "2.1.0-beta.20",
|
|
39
|
+
"@apibara/protocol": "2.1.0-beta.20"
|
|
40
40
|
}
|
|
41
41
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { useIndexerContext } from "@apibara/indexer";
|
|
2
|
-
import { defineIndexerPlugin } from "@apibara/indexer/plugins";
|
|
2
|
+
import { defineIndexerPlugin, useLogger } from "@apibara/indexer/plugins";
|
|
3
3
|
import type { DbOptions, MongoClient } from "mongodb";
|
|
4
4
|
|
|
5
5
|
import { generateIndexerId } from "@apibara/indexer/internal";
|
|
6
6
|
import { useInternalContext } from "@apibara/indexer/internal/plugins";
|
|
7
|
-
import {
|
|
7
|
+
import type { Cursor, DataFinality } from "@apibara/protocol";
|
|
8
|
+
import { cleanupStorage, finalize, invalidate } from "./mongo";
|
|
8
9
|
import {
|
|
9
10
|
finalizeState,
|
|
10
11
|
getState,
|
|
11
12
|
initializePersistentState,
|
|
12
13
|
invalidateState,
|
|
13
14
|
persistState,
|
|
15
|
+
resetPersistence,
|
|
14
16
|
} from "./persistence";
|
|
15
17
|
import { MongoStorage } from "./storage";
|
|
16
18
|
import { MongoStorageError, withTransaction } from "./utils";
|
|
@@ -60,10 +62,31 @@ export function mongoStorage<TFilter, TBlock>({
|
|
|
60
62
|
}: MongoStorageOptions) {
|
|
61
63
|
return defineIndexerPlugin<TFilter, TBlock>((indexer) => {
|
|
62
64
|
let indexerId = "";
|
|
65
|
+
const alwaysReindex = process.env["APIBARA_ALWAYS_REINDEX"] === "true";
|
|
66
|
+
let prevFinality: DataFinality | undefined;
|
|
63
67
|
|
|
64
68
|
indexer.hooks.hook("run:before", async () => {
|
|
65
69
|
const { indexerName } = useInternalContext();
|
|
66
70
|
indexerId = generateIndexerId(indexerName, identifier);
|
|
71
|
+
const logger = useLogger();
|
|
72
|
+
|
|
73
|
+
if (alwaysReindex) {
|
|
74
|
+
logger.warn(
|
|
75
|
+
`Reindexing: Deleting all data from collections - ${collections.join(", ")}`,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
await withTransaction(client, async (session) => {
|
|
79
|
+
const db = client.db(dbName, dbOptions);
|
|
80
|
+
|
|
81
|
+
await cleanupStorage(db, session, collections);
|
|
82
|
+
|
|
83
|
+
if (enablePersistence) {
|
|
84
|
+
await resetPersistence({ db, session, indexerId });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
logger.success("All data has been cleaned up for reindexing");
|
|
88
|
+
});
|
|
89
|
+
}
|
|
67
90
|
|
|
68
91
|
await withTransaction(client, async (session) => {
|
|
69
92
|
const db = client.db(dbName, dbOptions);
|
|
@@ -168,7 +191,11 @@ export function mongoStorage<TFilter, TBlock>({
|
|
|
168
191
|
|
|
169
192
|
indexer.hooks.hook("handler:middleware", async ({ use }) => {
|
|
170
193
|
use(async (context, next) => {
|
|
171
|
-
const { endCursor } = context
|
|
194
|
+
const { endCursor, finality, cursor } = context as {
|
|
195
|
+
cursor: Cursor;
|
|
196
|
+
endCursor: Cursor;
|
|
197
|
+
finality: DataFinality;
|
|
198
|
+
};
|
|
172
199
|
|
|
173
200
|
if (!endCursor) {
|
|
174
201
|
throw new MongoStorageError("end cursor is undefined");
|
|
@@ -178,10 +205,16 @@ export function mongoStorage<TFilter, TBlock>({
|
|
|
178
205
|
const db = client.db(dbName, dbOptions);
|
|
179
206
|
context[MONGO_PROPERTY] = new MongoStorage(db, session, endCursor);
|
|
180
207
|
|
|
208
|
+
if (prevFinality === "pending") {
|
|
209
|
+
// invalidate if previous block's finality was "pending"
|
|
210
|
+
await invalidate(db, session, cursor, collections);
|
|
211
|
+
}
|
|
212
|
+
|
|
181
213
|
await next();
|
|
214
|
+
|
|
182
215
|
delete context[MONGO_PROPERTY];
|
|
183
216
|
|
|
184
|
-
if (enablePersistence) {
|
|
217
|
+
if (enablePersistence && finality !== "pending") {
|
|
185
218
|
await persistState({
|
|
186
219
|
db,
|
|
187
220
|
endCursor,
|
|
@@ -189,6 +222,8 @@ export function mongoStorage<TFilter, TBlock>({
|
|
|
189
222
|
indexerId,
|
|
190
223
|
});
|
|
191
224
|
}
|
|
225
|
+
|
|
226
|
+
prevFinality = finality;
|
|
192
227
|
});
|
|
193
228
|
});
|
|
194
229
|
});
|
package/src/mongo.ts
CHANGED
|
@@ -49,3 +49,20 @@ export async function finalize(
|
|
|
49
49
|
);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
+
|
|
53
|
+
export async function cleanupStorage(
|
|
54
|
+
db: Db,
|
|
55
|
+
session: ClientSession,
|
|
56
|
+
collections: string[],
|
|
57
|
+
) {
|
|
58
|
+
for (const collection of collections) {
|
|
59
|
+
try {
|
|
60
|
+
// Delete all documents in the collection
|
|
61
|
+
await db.collection(collection).deleteMany({}, { session });
|
|
62
|
+
} catch (error) {
|
|
63
|
+
throw new Error(`Failed to clean up collection ${collection}`, {
|
|
64
|
+
cause: error,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
package/src/persistence.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Cursor, normalizeCursor } from "@apibara/protocol";
|
|
2
2
|
import type { ClientSession, Db } from "mongodb";
|
|
3
|
+
import { MongoStorageError } from "./utils";
|
|
3
4
|
|
|
4
5
|
export type CheckpointSchema = {
|
|
5
6
|
id: string;
|
|
@@ -21,13 +22,8 @@ export async function initializePersistentState(
|
|
|
21
22
|
db: Db,
|
|
22
23
|
session: ClientSession,
|
|
23
24
|
) {
|
|
24
|
-
const checkpoint =
|
|
25
|
-
|
|
26
|
-
{ session },
|
|
27
|
-
);
|
|
28
|
-
const filter = await db.createCollection<FilterSchema>(filterCollectionName, {
|
|
29
|
-
session,
|
|
30
|
-
});
|
|
25
|
+
const checkpoint = db.collection<CheckpointSchema>(checkpointCollectionName);
|
|
26
|
+
const filter = db.collection<FilterSchema>(filterCollectionName);
|
|
31
27
|
|
|
32
28
|
await checkpoint.createIndex({ id: 1 }, { session });
|
|
33
29
|
await filter.createIndex({ id: 1, fromBlock: 1 }, { session });
|
|
@@ -48,7 +44,7 @@ export async function persistState<TFilter>(props: {
|
|
|
48
44
|
{
|
|
49
45
|
$set: {
|
|
50
46
|
orderKey: Number(endCursor.orderKey),
|
|
51
|
-
uniqueKey: endCursor.uniqueKey,
|
|
47
|
+
uniqueKey: endCursor.uniqueKey ? endCursor.uniqueKey : null,
|
|
52
48
|
},
|
|
53
49
|
},
|
|
54
50
|
{ upsert: true, session },
|
|
@@ -161,3 +157,27 @@ export async function finalizeState(props: {
|
|
|
161
157
|
{ session },
|
|
162
158
|
);
|
|
163
159
|
}
|
|
160
|
+
|
|
161
|
+
export async function resetPersistence(props: {
|
|
162
|
+
db: Db;
|
|
163
|
+
session: ClientSession;
|
|
164
|
+
indexerId: string;
|
|
165
|
+
}) {
|
|
166
|
+
const { db, session, indexerId } = props;
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
// Delete all checkpoints for this indexer
|
|
170
|
+
await db
|
|
171
|
+
.collection<CheckpointSchema>(checkpointCollectionName)
|
|
172
|
+
.deleteMany({ id: indexerId }, { session });
|
|
173
|
+
|
|
174
|
+
// Delete all filters for this indexer
|
|
175
|
+
await db
|
|
176
|
+
.collection<FilterSchema>(filterCollectionName)
|
|
177
|
+
.deleteMany({ id: indexerId }, { session });
|
|
178
|
+
} catch (error) {
|
|
179
|
+
throw new MongoStorageError("Failed to reset persistence state", {
|
|
180
|
+
cause: error,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ClientSession, MongoClient } from "mongodb";
|
|
2
2
|
|
|
3
3
|
export class MongoStorageError extends Error {
|
|
4
|
-
constructor(message: string) {
|
|
5
|
-
super(message);
|
|
4
|
+
constructor(message: string, options?: ErrorOptions) {
|
|
5
|
+
super(message, options);
|
|
6
6
|
this.name = "MongoStorageError";
|
|
7
7
|
}
|
|
8
8
|
}
|
|
@@ -12,8 +12,13 @@ export async function withTransaction<T>(
|
|
|
12
12
|
cb: (session: ClientSession) => Promise<T>,
|
|
13
13
|
) {
|
|
14
14
|
return await client.withSession(async (session) => {
|
|
15
|
-
return await session.withTransaction(
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
return await session.withTransaction(
|
|
16
|
+
async (session) => {
|
|
17
|
+
return await cb(session);
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
retryWrites: false,
|
|
21
|
+
},
|
|
22
|
+
);
|
|
18
23
|
});
|
|
19
24
|
}
|