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.
@@ -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
- sources: new Set(sources),
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 queries = FetchState.getNextQuery(fetchState, sourceManager.maxPartitionConcurrency - sourceManager.fetchingPartitionsCount | 0, currentBlockHeight, stateId);
74
- if (typeof queries !== "object") {
75
- switch (queries) {
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 currentBlockHeight$1 = await waitForNewBlock(currentBlockHeight);
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(currentBlockHeight$1);
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$1 = queries._0;
99
- FetchState.startFetchingQueries(fetchState, queries$1, stateId);
100
- sourceManager.fetchingPartitionsCount = sourceManager.fetchingPartitionsCount + queries$1.length | 0;
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$1, (function (q) {
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
- async function getSourceNewHeight(sourceManager, source, currentBlockHeight, status, logger) {
120
- var newHeight = 0;
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 <= currentBlockHeight && status.contents !== "Done") {
123
- try {
124
- var endTimer = Prometheus.SourceGetHeightDuration.startTimer({
125
- source: source.name,
126
- chainId: source.chain
127
- });
128
- var height = await source.getHeightOrThrow();
129
- endTimer();
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
- catch (raw_exn){
139
- var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
140
- var retryInterval = sourceManager.getHeightRetryInterval(retry);
141
- Logging.childTrace(logger, {
142
- msg: "Height retrieval from " + source.name + " source failed. Retrying in " + String(retryInterval) + "ms.",
143
- source: source.name,
144
- err: Utils.prettifyExn(exn)
145
- });
146
- retry = retry + 1 | 0;
147
- await Utils.delay(retryInterval);
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
- Prometheus.SourceHeight.set(source.name, source.chain, newHeight);
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, currentBlockHeight) {
203
+ async function waitForNewBlock(sourceManager, knownHeight) {
155
204
  var logger = Logging.createChild({
156
205
  chainId: sourceManager.activeSource.chain,
157
- currentBlockHeight: currentBlockHeight
206
+ knownHeight: knownHeight
158
207
  });
159
208
  Logging.childTrace(logger, "Initiating check for new blocks.");
160
209
  var syncSources = [];
161
210
  var fallbackSources = [];
162
- sourceManager.sources.forEach(function (source) {
163
- if (source.sourceFor === "Sync" || source === sourceManager.activeSource) {
164
- syncSources.push(source);
165
- } else {
166
- fallbackSources.push(source);
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 (source) {
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, source, currentBlockHeight, status, logger)
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 (source) {
241
+ return Promise.race(Belt_Array.map(fallbackSources, (async function (sourceState) {
187
242
  return [
188
- source,
189
- await getSourceNewHeight(sourceManager, source, currentBlockHeight, status, logger)
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 getNextSyncSource(sourceManager, initialSource, currentSource, attemptFallbacksOpt) {
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
- sourceManager.sources.forEach(function (source) {
214
- if (source === currentSource) {
215
- hasActive.contents = true;
216
- return ;
217
- }
218
- var match = source.sourceFor;
219
- var tmp;
220
- tmp = match === "Sync" ? true : attemptFallbacks || source === initialSource;
221
- if (tmp) {
222
- (
223
- hasActive.contents ? after : before
224
- ).push(source);
225
- return ;
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 currentSource;
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 initialSource = sourceManager.activeSource;
250
- var sourceRef = initialSource;
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 source = sourceRef;
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 nextSource = !(retry === 0 || retry === 1) && retry % 2 === 0 ? getNextSyncSource(sourceManager, initialSource, source, attemptFallbacks) : source;
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 = nextSource !== source;
376
+ var shouldSwitch = nextSourceState !== sourceState;
314
377
  if (shouldSwitch) {
315
378
  Logging.childInfo(logger, {
316
379
  msg: "Switching to another data-source",
317
- source: nextSource.name
380
+ source: nextSourceState.source.name
318
381
  });
319
- sourceRef = nextSource;
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 nextSource$1 = getNextSyncSource(sourceManager, initialSource, source, true);
328
- var hasAnotherSource = nextSource$1 !== initialSource;
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
- sourceRef = nextSource$1;
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 nextSource$2 = getNextSyncSource(sourceManager, initialSource, source, undefined);
351
- var notAlreadyDeleted = sourceManager.sources.delete(source);
352
- if (notAlreadyDeleted) {
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 (nextSource$2 === source) {
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: nextSource$2.name
438
+ source: nextSourceState$2.source.name
376
439
  });
377
- sourceRef = nextSource$2;
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 = sourceRef;
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: (~currentBlockHeight: int) => promise<int>,
19
- ~onNewBlock: (~currentBlockHeight: int) => unit,
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, ~currentBlockHeight: int) => promise<int>
23
+ let waitForNewBlock: (t, ~knownHeight: int) => promise<int>
24
24
 
25
25
  let executeQuery: (
26
26
  t,