envio 2.32.3 → 2.32.7
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/package.json +12 -11
- package/src/Utils.res +9 -0
- package/src/Utils.res.js +18 -0
- package/src/bindings/EventSource.res +20 -0
- package/src/bindings/EventSource.res.js +8 -0
- package/src/sources/HyperSync.res +10 -2
- package/src/sources/HyperSync.res.js +9 -4
- package/src/sources/HyperSyncClient.res +77 -20
- package/src/sources/HyperSyncClient.res.js +22 -6
- package/src/sources/HyperSyncHeightStream.res +105 -0
- package/src/sources/HyperSyncHeightStream.res.js +97 -0
- package/src/sources/HyperSyncSource.res +12 -1
- package/src/sources/HyperSyncSource.res.js +13 -3
- package/src/sources/Source.res +1 -0
- package/src/sources/SourceManager.res +172 -95
- package/src/sources/SourceManager.res.js +150 -87
- package/src/sources/SourceManager.resi +3 -3
|
@@ -11,6 +11,7 @@ var Belt_Array = require("rescript/lib/js/belt_Array.js");
|
|
|
11
11
|
var FetchState = require("../FetchState.res.js");
|
|
12
12
|
var Prometheus = require("../Prometheus.res.js");
|
|
13
13
|
var Belt_Option = require("rescript/lib/js/belt_Option.js");
|
|
14
|
+
var Caml_option = require("rescript/lib/js/caml_option.js");
|
|
14
15
|
var ErrorHandling = require("../ErrorHandling.res.js");
|
|
15
16
|
var Caml_js_exceptions = require("rescript/lib/js/caml_js_exceptions.js");
|
|
16
17
|
|
|
@@ -36,7 +37,15 @@ function make(sources, maxPartitionConcurrency, newBlockFallbackStallTimeoutOpt,
|
|
|
36
37
|
Prometheus.IndexingMaxConcurrency.set(maxPartitionConcurrency, initialActiveSource.chain);
|
|
37
38
|
Prometheus.IndexingConcurrency.set(0, initialActiveSource.chain);
|
|
38
39
|
return {
|
|
39
|
-
|
|
40
|
+
sourcesState: Belt_Array.map(sources, (function (source) {
|
|
41
|
+
return {
|
|
42
|
+
source: source,
|
|
43
|
+
knownHeight: 0,
|
|
44
|
+
unsubscribe: undefined,
|
|
45
|
+
pendingHeightResolvers: [],
|
|
46
|
+
disabled: false
|
|
47
|
+
};
|
|
48
|
+
})),
|
|
40
49
|
statusStart: Hrtime.makeTimer(),
|
|
41
50
|
status: "Idle",
|
|
42
51
|
maxPartitionConcurrency: maxPartitionConcurrency,
|
|
@@ -70,9 +79,9 @@ function trackNewStatus(sourceManager, newStatus) {
|
|
|
70
79
|
}
|
|
71
80
|
|
|
72
81
|
async function fetchNext(sourceManager, fetchState, currentBlockHeight, executeQuery, waitForNewBlock, onNewBlock, stateId) {
|
|
73
|
-
var
|
|
74
|
-
if (typeof
|
|
75
|
-
switch (
|
|
82
|
+
var nextQuery = FetchState.getNextQuery(fetchState, sourceManager.maxPartitionConcurrency - sourceManager.fetchingPartitionsCount | 0, currentBlockHeight, stateId);
|
|
83
|
+
if (typeof nextQuery !== "object") {
|
|
84
|
+
switch (nextQuery) {
|
|
76
85
|
case "WaitingForNewBlock" :
|
|
77
86
|
var waitingStateId = sourceManager.waitingForNewBlockStateId;
|
|
78
87
|
if (waitingStateId !== undefined && waitingStateId >= stateId) {
|
|
@@ -80,12 +89,12 @@ async function fetchNext(sourceManager, fetchState, currentBlockHeight, executeQ
|
|
|
80
89
|
}
|
|
81
90
|
trackNewStatus(sourceManager, "WaitingForNewBlock");
|
|
82
91
|
sourceManager.waitingForNewBlockStateId = stateId;
|
|
83
|
-
var
|
|
92
|
+
var knownHeight = await waitForNewBlock(currentBlockHeight);
|
|
84
93
|
var waitingStateId$1 = sourceManager.waitingForNewBlockStateId;
|
|
85
94
|
if (waitingStateId$1 !== undefined && waitingStateId$1 === stateId) {
|
|
86
95
|
trackNewStatus(sourceManager, "Idle");
|
|
87
96
|
sourceManager.waitingForNewBlockStateId = undefined;
|
|
88
|
-
return onNewBlock(
|
|
97
|
+
return onNewBlock(knownHeight);
|
|
89
98
|
} else {
|
|
90
99
|
return ;
|
|
91
100
|
}
|
|
@@ -95,12 +104,12 @@ async function fetchNext(sourceManager, fetchState, currentBlockHeight, executeQ
|
|
|
95
104
|
|
|
96
105
|
}
|
|
97
106
|
} else {
|
|
98
|
-
var queries
|
|
99
|
-
FetchState.startFetchingQueries(fetchState, queries
|
|
100
|
-
sourceManager.fetchingPartitionsCount = sourceManager.fetchingPartitionsCount + queries
|
|
107
|
+
var queries = nextQuery._0;
|
|
108
|
+
FetchState.startFetchingQueries(fetchState, queries, stateId);
|
|
109
|
+
sourceManager.fetchingPartitionsCount = sourceManager.fetchingPartitionsCount + queries.length | 0;
|
|
101
110
|
Prometheus.IndexingConcurrency.set(sourceManager.fetchingPartitionsCount, sourceManager.activeSource.chain);
|
|
102
111
|
trackNewStatus(sourceManager, "Querieng");
|
|
103
|
-
await Promise.all(Belt_Array.map(queries
|
|
112
|
+
await Promise.all(Belt_Array.map(queries, (function (q) {
|
|
104
113
|
var promise = executeQuery(q);
|
|
105
114
|
promise.then(function (param) {
|
|
106
115
|
sourceManager.fetchingPartitionsCount = sourceManager.fetchingPartitionsCount - 1 | 0;
|
|
@@ -116,63 +125,109 @@ async function fetchNext(sourceManager, fetchState, currentBlockHeight, executeQ
|
|
|
116
125
|
}
|
|
117
126
|
}
|
|
118
127
|
|
|
119
|
-
|
|
120
|
-
|
|
128
|
+
function disableSource(sourceState) {
|
|
129
|
+
if (sourceState.disabled) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
sourceState.disabled = true;
|
|
133
|
+
var unsubscribe = sourceState.unsubscribe;
|
|
134
|
+
if (unsubscribe !== undefined) {
|
|
135
|
+
unsubscribe();
|
|
136
|
+
}
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function getSourceNewHeight(sourceManager, sourceState, knownHeight, status, logger) {
|
|
141
|
+
var source = sourceState.source;
|
|
142
|
+
var initialHeight = sourceState.knownHeight;
|
|
143
|
+
var newHeight = initialHeight;
|
|
121
144
|
var retry = 0;
|
|
122
|
-
while(newHeight <=
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
newHeight = height;
|
|
131
|
-
if (height <= currentBlockHeight) {
|
|
132
|
-
retry = 0;
|
|
133
|
-
var pollingInterval = status.contents === "Stalled" ? sourceManager.stalledPollingInterval : source.pollingInterval;
|
|
134
|
-
await Utils.delay(pollingInterval);
|
|
145
|
+
while(newHeight <= knownHeight && status.contents !== "Done") {
|
|
146
|
+
var match = sourceState.unsubscribe;
|
|
147
|
+
if (match !== undefined) {
|
|
148
|
+
var height = await new Promise((function (resolve, _reject) {
|
|
149
|
+
sourceState.pendingHeightResolvers.push(resolve);
|
|
150
|
+
}));
|
|
151
|
+
if (height > initialHeight) {
|
|
152
|
+
newHeight = height;
|
|
135
153
|
}
|
|
136
154
|
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
155
|
+
} else {
|
|
156
|
+
try {
|
|
157
|
+
var endTimer = Prometheus.SourceGetHeightDuration.startTimer({
|
|
158
|
+
source: source.name,
|
|
159
|
+
chainId: source.chain
|
|
160
|
+
});
|
|
161
|
+
var height$1 = await source.getHeightOrThrow();
|
|
162
|
+
endTimer();
|
|
163
|
+
newHeight = height$1;
|
|
164
|
+
if (height$1 <= knownHeight) {
|
|
165
|
+
retry = 0;
|
|
166
|
+
var createSubscription = source.createHeightSubscription;
|
|
167
|
+
if (createSubscription !== undefined) {
|
|
168
|
+
var unsubscribe = createSubscription(function (newHeight) {
|
|
169
|
+
sourceState.knownHeight = newHeight;
|
|
170
|
+
var resolvers = sourceState.pendingHeightResolvers;
|
|
171
|
+
sourceState.pendingHeightResolvers = [];
|
|
172
|
+
Belt_Array.forEach(resolvers, (function (resolve) {
|
|
173
|
+
resolve(newHeight);
|
|
174
|
+
}));
|
|
175
|
+
});
|
|
176
|
+
sourceState.unsubscribe = unsubscribe;
|
|
177
|
+
} else {
|
|
178
|
+
var pollingInterval = status.contents === "Stalled" ? sourceManager.stalledPollingInterval : source.pollingInterval;
|
|
179
|
+
await Utils.delay(pollingInterval);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
catch (raw_exn){
|
|
185
|
+
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
186
|
+
var retryInterval = sourceManager.getHeightRetryInterval(retry);
|
|
187
|
+
Logging.childTrace(logger, {
|
|
188
|
+
msg: "Height retrieval from " + source.name + " source failed. Retrying in " + String(retryInterval) + "ms.",
|
|
189
|
+
source: source.name,
|
|
190
|
+
err: Utils.prettifyExn(exn)
|
|
191
|
+
});
|
|
192
|
+
retry = retry + 1 | 0;
|
|
193
|
+
await Utils.delay(retryInterval);
|
|
194
|
+
}
|
|
148
195
|
}
|
|
149
196
|
};
|
|
150
|
-
|
|
197
|
+
if (newHeight > initialHeight) {
|
|
198
|
+
Prometheus.SourceHeight.set(source.name, source.chain, newHeight);
|
|
199
|
+
}
|
|
151
200
|
return newHeight;
|
|
152
201
|
}
|
|
153
202
|
|
|
154
|
-
async function waitForNewBlock(sourceManager,
|
|
203
|
+
async function waitForNewBlock(sourceManager, knownHeight) {
|
|
155
204
|
var logger = Logging.createChild({
|
|
156
205
|
chainId: sourceManager.activeSource.chain,
|
|
157
|
-
|
|
206
|
+
knownHeight: knownHeight
|
|
158
207
|
});
|
|
159
208
|
Logging.childTrace(logger, "Initiating check for new blocks.");
|
|
160
209
|
var syncSources = [];
|
|
161
210
|
var fallbackSources = [];
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
211
|
+
Belt_Array.forEach(sourceManager.sourcesState, (function (sourceState) {
|
|
212
|
+
var source = sourceState.source;
|
|
213
|
+
if (sourceState.disabled) {
|
|
214
|
+
return ;
|
|
215
|
+
} else {
|
|
216
|
+
if (source.sourceFor === "Sync" || source === sourceManager.activeSource) {
|
|
217
|
+
syncSources.push(sourceState);
|
|
218
|
+
} else {
|
|
219
|
+
fallbackSources.push(sourceState);
|
|
220
|
+
}
|
|
221
|
+
return ;
|
|
222
|
+
}
|
|
223
|
+
}));
|
|
169
224
|
var status = {
|
|
170
225
|
contents: "Active"
|
|
171
226
|
};
|
|
172
|
-
var match = await Promise.race(Belt_Array.concat(Belt_Array.map(syncSources, (async function (
|
|
227
|
+
var match = await Promise.race(Belt_Array.concat(Belt_Array.map(syncSources, (async function (sourceState) {
|
|
173
228
|
return [
|
|
174
|
-
source,
|
|
175
|
-
await getSourceNewHeight(sourceManager,
|
|
229
|
+
sourceState.source,
|
|
230
|
+
await getSourceNewHeight(sourceManager, sourceState, knownHeight, status, logger)
|
|
176
231
|
];
|
|
177
232
|
})), [Utils.delay(sourceManager.newBlockFallbackStallTimeout).then(function () {
|
|
178
233
|
if (status.contents !== "Done") {
|
|
@@ -183,10 +238,10 @@ async function waitForNewBlock(sourceManager, currentBlockHeight) {
|
|
|
183
238
|
Logging.childWarn(logger, "No new blocks detected within " + String(sourceManager.newBlockFallbackStallTimeout / 1000 | 0) + "s. Polling will continue at a reduced rate. For better reliability, refer to our RPC fallback guide: https://docs.envio.dev/docs/HyperIndex/rpc-sync");
|
|
184
239
|
}
|
|
185
240
|
}
|
|
186
|
-
return Promise.race(Belt_Array.map(fallbackSources, (async function (
|
|
241
|
+
return Promise.race(Belt_Array.map(fallbackSources, (async function (sourceState) {
|
|
187
242
|
return [
|
|
188
|
-
source,
|
|
189
|
-
await getSourceNewHeight(sourceManager,
|
|
243
|
+
sourceState.source,
|
|
244
|
+
await getSourceNewHeight(sourceManager, sourceState, knownHeight, status, logger)
|
|
190
245
|
];
|
|
191
246
|
})));
|
|
192
247
|
})]));
|
|
@@ -203,29 +258,33 @@ async function waitForNewBlock(sourceManager, currentBlockHeight) {
|
|
|
203
258
|
return newBlockHeight;
|
|
204
259
|
}
|
|
205
260
|
|
|
206
|
-
function
|
|
261
|
+
function getNextSyncSourceState(sourceManager, initialSourceState, currentSourceState, attemptFallbacksOpt) {
|
|
207
262
|
var attemptFallbacks = attemptFallbacksOpt !== undefined ? attemptFallbacksOpt : false;
|
|
208
263
|
var before = [];
|
|
209
264
|
var after = [];
|
|
210
265
|
var hasActive = {
|
|
211
266
|
contents: false
|
|
212
267
|
};
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
268
|
+
Belt_Array.forEach(sourceManager.sourcesState, (function (sourceState) {
|
|
269
|
+
var source = sourceState.source;
|
|
270
|
+
if (sourceState.disabled) {
|
|
271
|
+
return ;
|
|
272
|
+
}
|
|
273
|
+
if (sourceState === currentSourceState) {
|
|
274
|
+
hasActive.contents = true;
|
|
275
|
+
return ;
|
|
276
|
+
}
|
|
277
|
+
var match = source.sourceFor;
|
|
278
|
+
var tmp;
|
|
279
|
+
tmp = match === "Sync" ? true : attemptFallbacks || sourceState === initialSourceState;
|
|
280
|
+
if (tmp) {
|
|
281
|
+
(
|
|
282
|
+
hasActive.contents ? after : before
|
|
283
|
+
).push(sourceState);
|
|
284
|
+
return ;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
}));
|
|
229
288
|
var s = Belt_Array.get(after, 0);
|
|
230
289
|
if (s !== undefined) {
|
|
231
290
|
return s;
|
|
@@ -234,7 +293,7 @@ function getNextSyncSource(sourceManager, initialSource, currentSource, attemptF
|
|
|
234
293
|
if (s$1 !== undefined) {
|
|
235
294
|
return s$1;
|
|
236
295
|
} else {
|
|
237
|
-
return
|
|
296
|
+
return currentSourceState;
|
|
238
297
|
}
|
|
239
298
|
}
|
|
240
299
|
|
|
@@ -246,11 +305,15 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
246
305
|
);
|
|
247
306
|
var responseRef;
|
|
248
307
|
var retryRef = 0;
|
|
249
|
-
var
|
|
250
|
-
|
|
308
|
+
var initialSourceState = sourceManager.sourcesState.find(function (s) {
|
|
309
|
+
return s.source === sourceManager.activeSource;
|
|
310
|
+
});
|
|
311
|
+
var initialSourceState$1 = initialSourceState === undefined ? undefined : Caml_option.some(initialSourceState);
|
|
312
|
+
var sourceStateRef = initialSourceState$1;
|
|
251
313
|
var shouldUpdateActiveSource = false;
|
|
252
314
|
while(Belt_Option.isNone(responseRef)) {
|
|
253
|
-
var
|
|
315
|
+
var sourceState = sourceStateRef;
|
|
316
|
+
var source = sourceState.source;
|
|
254
317
|
var toBlock = toBlockRef;
|
|
255
318
|
var retry = retryRef;
|
|
256
319
|
var logger = Logging.createChild({
|
|
@@ -301,7 +364,7 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
301
364
|
case "WithBackoff" :
|
|
302
365
|
var backoffMillis = match$1.backoffMillis;
|
|
303
366
|
var attemptFallbacks = retry >= 10;
|
|
304
|
-
var
|
|
367
|
+
var nextSourceState = !(retry === 0 || retry === 1) && retry % 2 === 0 ? getNextSyncSourceState(sourceManager, initialSourceState$1, sourceState, attemptFallbacks) : sourceState;
|
|
305
368
|
var log = retry >= 4 ? Logging.childWarn : Logging.childTrace;
|
|
306
369
|
log(logger, {
|
|
307
370
|
msg: match$1.message,
|
|
@@ -310,13 +373,13 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
310
373
|
retry: retry,
|
|
311
374
|
err: Utils.prettifyExn(exn)
|
|
312
375
|
});
|
|
313
|
-
var shouldSwitch =
|
|
376
|
+
var shouldSwitch = nextSourceState !== sourceState;
|
|
314
377
|
if (shouldSwitch) {
|
|
315
378
|
Logging.childInfo(logger, {
|
|
316
379
|
msg: "Switching to another data-source",
|
|
317
|
-
source:
|
|
380
|
+
source: nextSourceState.source.name
|
|
318
381
|
});
|
|
319
|
-
|
|
382
|
+
sourceStateRef = nextSourceState;
|
|
320
383
|
shouldUpdateActiveSource = true;
|
|
321
384
|
} else {
|
|
322
385
|
await Utils.delay(backoffMillis < 60000 ? backoffMillis : 60000);
|
|
@@ -324,8 +387,8 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
324
387
|
retryRef = retryRef + 1 | 0;
|
|
325
388
|
break;
|
|
326
389
|
case "ImpossibleForTheQuery" :
|
|
327
|
-
var
|
|
328
|
-
var hasAnotherSource =
|
|
390
|
+
var nextSourceState$1 = getNextSyncSourceState(sourceManager, initialSourceState$1, sourceState, true);
|
|
391
|
+
var hasAnotherSource = nextSourceState$1 !== initialSourceState$1;
|
|
329
392
|
Logging.childWarn(logger, {
|
|
330
393
|
msg: match$1.message + (
|
|
331
394
|
hasAnotherSource ? " - Attempting to another source" : ""
|
|
@@ -334,7 +397,7 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
334
397
|
err: Utils.prettifyExn(exn)
|
|
335
398
|
});
|
|
336
399
|
if (hasAnotherSource) {
|
|
337
|
-
|
|
400
|
+
sourceStateRef = nextSourceState$1;
|
|
338
401
|
shouldUpdateActiveSource = false;
|
|
339
402
|
retryRef = 0;
|
|
340
403
|
} else {
|
|
@@ -347,9 +410,9 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
347
410
|
|
|
348
411
|
}
|
|
349
412
|
if (exit === 1) {
|
|
350
|
-
var
|
|
351
|
-
var
|
|
352
|
-
if (
|
|
413
|
+
var nextSourceState$2 = getNextSyncSourceState(sourceManager, initialSourceState$1, sourceState, undefined);
|
|
414
|
+
var notAlreadyDisabled = disableSource(sourceState);
|
|
415
|
+
if (notAlreadyDisabled) {
|
|
353
416
|
switch (error$1.TAG) {
|
|
354
417
|
case "UnsupportedSelection" :
|
|
355
418
|
Logging.childError(logger, error$1.message);
|
|
@@ -367,14 +430,14 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
367
430
|
|
|
368
431
|
}
|
|
369
432
|
}
|
|
370
|
-
if (
|
|
433
|
+
if (nextSourceState$2 === sourceState) {
|
|
371
434
|
ErrorHandling.mkLogAndRaise(logger, "The indexer doesn't have data-sources which can continue fetching. Please, check the error logs or reach out to the Envio team.", null);
|
|
372
435
|
} else {
|
|
373
436
|
Logging.childInfo(logger, {
|
|
374
437
|
msg: "Switching to another data-source",
|
|
375
|
-
source:
|
|
438
|
+
source: nextSourceState$2.source.name
|
|
376
439
|
});
|
|
377
|
-
|
|
440
|
+
sourceStateRef = nextSourceState$2;
|
|
378
441
|
shouldUpdateActiveSource = true;
|
|
379
442
|
retryRef = 0;
|
|
380
443
|
}
|
|
@@ -386,7 +449,7 @@ async function executeQuery(sourceManager, query, currentBlockHeight) {
|
|
|
386
449
|
}
|
|
387
450
|
};
|
|
388
451
|
if (shouldUpdateActiveSource) {
|
|
389
|
-
sourceManager.activeSource =
|
|
452
|
+
sourceManager.activeSource = sourceStateRef.source;
|
|
390
453
|
}
|
|
391
454
|
return responseRef;
|
|
392
455
|
}
|
|
@@ -15,12 +15,12 @@ let fetchNext: (
|
|
|
15
15
|
~fetchState: FetchState.t,
|
|
16
16
|
~currentBlockHeight: int,
|
|
17
17
|
~executeQuery: FetchState.query => promise<unit>,
|
|
18
|
-
~waitForNewBlock: (~
|
|
19
|
-
~onNewBlock: (~
|
|
18
|
+
~waitForNewBlock: (~knownHeight: int) => promise<int>,
|
|
19
|
+
~onNewBlock: (~knownHeight: int) => unit,
|
|
20
20
|
~stateId: int,
|
|
21
21
|
) => promise<unit>
|
|
22
22
|
|
|
23
|
-
let waitForNewBlock: (t, ~
|
|
23
|
+
let waitForNewBlock: (t, ~knownHeight: int) => promise<int>
|
|
24
24
|
|
|
25
25
|
let executeQuery: (
|
|
26
26
|
t,
|