@lido-nestjs/execution 1.14.2 → 1.16.0
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/error/codes/error-codes.d.ts +2 -1
- package/dist/error/codes/error-codes.js +1 -0
- package/dist/error/index.d.ts +1 -0
- package/dist/error/request-timeout.error.d.ts +5 -0
- package/dist/error/request-timeout.error.js +14 -0
- package/dist/index.js +2 -0
- package/dist/interfaces/simple-fallback-provider-config.d.ts +2 -0
- package/dist/provider/simple-fallback-json-rpc-batch-provider.d.ts +2 -0
- package/dist/provider/simple-fallback-json-rpc-batch-provider.js +74 -9
- package/package.json +1 -1
|
@@ -6,4 +6,5 @@ exports.ErrorCode = void 0;
|
|
|
6
6
|
(function (ErrorCode) {
|
|
7
7
|
ErrorCode["UNEXPECTED_BATCH_RESULT"] = "UNEXPECTED_BATCH_RESULT";
|
|
8
8
|
ErrorCode["PARTIAL_BATCH_RESULT"] = "PARTIAL_BATCH_RESULT";
|
|
9
|
+
ErrorCode["REQUEST_TIMEOUT"] = "REQUEST_TIMEOUT";
|
|
9
10
|
})(exports.ErrorCode || (exports.ErrorCode = {}));
|
package/dist/error/index.d.ts
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
class RequestTimeoutError extends Error {
|
|
6
|
+
constructor(message, timeoutMs) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'RequestTimeoutError';
|
|
9
|
+
this.timeoutMs = timeoutMs;
|
|
10
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
exports.RequestTimeoutError = RequestTimeoutError;
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ var feeHistory = require('./ethers/fee-history.js');
|
|
|
11
11
|
var allProvidersFailed_error = require('./error/all-providers-failed.error.js');
|
|
12
12
|
var fetch_error = require('./error/fetch.error.js');
|
|
13
13
|
var noNewBlocksWhilePolling_error = require('./error/no-new-blocks-while-polling.error.js');
|
|
14
|
+
var requestTimeout_error = require('./error/request-timeout.error.js');
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
|
|
@@ -37,3 +38,4 @@ exports.getFeeHistory = feeHistory.getFeeHistory;
|
|
|
37
38
|
exports.AllProvidersFailedError = allProvidersFailed_error.AllProvidersFailedError;
|
|
38
39
|
exports.FetchError = fetch_error.FetchError;
|
|
39
40
|
exports.NoNewBlocksWhilePollingError = noNewBlocksWhilePolling_error.NoNewBlocksWhilePollingError;
|
|
41
|
+
exports.RequestTimeoutError = requestTimeout_error.RequestTimeoutError;
|
|
@@ -46,12 +46,14 @@ export declare class SimpleFallbackJsonRpcBatchProvider extends BaseProvider {
|
|
|
46
46
|
constructor(config: SimpleFallbackProviderConfig, logger: LoggerService);
|
|
47
47
|
static _formatter: Formatter | null;
|
|
48
48
|
static getFormatter(): Formatter;
|
|
49
|
+
protected formatLog(message: string, providerIndex?: number): string;
|
|
49
50
|
on(eventName: EventType, listener: Listener): this;
|
|
50
51
|
getFeeHistory(blockCount: number, newestBlock?: string | null | number, rewardPercentiles?: number[]): Promise<FeeHistory>;
|
|
51
52
|
getDebugTraceBlockByHash(blockHash: string, traceConfig: Partial<TraceConfig>): Promise<TraceResult[]>;
|
|
52
53
|
protected get provider(): FallbackProvider;
|
|
53
54
|
protected switchToNextProvider(): void;
|
|
54
55
|
protected isNonRetryableError(error: Error | unknown): boolean;
|
|
56
|
+
protected withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T>;
|
|
55
57
|
perform(method: string, params: {
|
|
56
58
|
[name: string]: unknown;
|
|
57
59
|
}): Promise<unknown>;
|
|
@@ -12,12 +12,14 @@ var networks = require('../common/networks.js');
|
|
|
12
12
|
var noNewBlocksWhilePolling_error = require('../error/no-new-blocks-while-polling.error.js');
|
|
13
13
|
var errors = require('../common/errors.js');
|
|
14
14
|
var allProvidersFailed_error = require('../error/all-providers-failed.error.js');
|
|
15
|
+
var requestTimeout_error = require('../error/request-timeout.error.js');
|
|
15
16
|
var feeHistory = require('../ethers/fee-history.js');
|
|
16
17
|
var debugTraceBlockByHash = require('../ethers/debug-trace-block-by-hash.js');
|
|
17
18
|
var events = require('events');
|
|
18
19
|
|
|
19
20
|
exports.SimpleFallbackJsonRpcBatchProvider = class SimpleFallbackJsonRpcBatchProvider extends providers.BaseProvider {
|
|
20
21
|
constructor(config, logger) {
|
|
22
|
+
var _a;
|
|
21
23
|
super(config.network);
|
|
22
24
|
this.detectNetworkFirstRun = true;
|
|
23
25
|
this.resetTimer = null;
|
|
@@ -54,6 +56,22 @@ exports.SimpleFallbackJsonRpcBatchProvider = class SimpleFallbackJsonRpcBatchPro
|
|
|
54
56
|
};
|
|
55
57
|
});
|
|
56
58
|
this.activeFallbackProviderIndex = 0;
|
|
59
|
+
// Log initialization info
|
|
60
|
+
const configInfo = {
|
|
61
|
+
providers: conns.length,
|
|
62
|
+
network: this.config.network,
|
|
63
|
+
requestPolicy: this.config.requestPolicy,
|
|
64
|
+
maxRetries: this.config.maxRetries,
|
|
65
|
+
minBackoffMs: this.config.minBackoffMs,
|
|
66
|
+
maxBackoffMs: this.config.maxBackoffMs,
|
|
67
|
+
logRetries: this.config.logRetries,
|
|
68
|
+
resetIntervalMs: this.config.resetIntervalMs,
|
|
69
|
+
fetchMiddlewares: ((_a = this.config.fetchMiddlewares) === null || _a === void 0 ? void 0 : _a.length) || 0,
|
|
70
|
+
maxTimeWithoutNewBlocksMs: this.config.maxTimeWithoutNewBlocksMs,
|
|
71
|
+
requestTimeoutMs: this.config.requestTimeoutMs || 'disabled',
|
|
72
|
+
instanceLabel: this.config.instanceLabel || 'none',
|
|
73
|
+
};
|
|
74
|
+
this.logger.log(this.formatLog(`Initialized SimpleFallbackJsonRpcBatchProvider: ${JSON.stringify(configInfo)}`));
|
|
57
75
|
}
|
|
58
76
|
static getFormatter() {
|
|
59
77
|
if (this._formatter == null) {
|
|
@@ -61,6 +79,19 @@ exports.SimpleFallbackJsonRpcBatchProvider = class SimpleFallbackJsonRpcBatchPro
|
|
|
61
79
|
}
|
|
62
80
|
return this._formatter;
|
|
63
81
|
}
|
|
82
|
+
formatLog(message, providerIndex) {
|
|
83
|
+
const parts = [];
|
|
84
|
+
if (this.config.instanceLabel) {
|
|
85
|
+
parts.push(`[${this.config.instanceLabel}]`);
|
|
86
|
+
}
|
|
87
|
+
if (providerIndex !== undefined) {
|
|
88
|
+
parts.push(`[provider:${providerIndex}]`);
|
|
89
|
+
}
|
|
90
|
+
if (parts.length > 0) {
|
|
91
|
+
return `${parts.join('')} ${message}`;
|
|
92
|
+
}
|
|
93
|
+
return message;
|
|
94
|
+
}
|
|
64
95
|
on(eventName, listener) {
|
|
65
96
|
let dieTimer = null;
|
|
66
97
|
const startDieTimer = (latestObservedBlockNumber) => {
|
|
@@ -109,17 +140,29 @@ exports.SimpleFallbackJsonRpcBatchProvider = class SimpleFallbackJsonRpcBatchPro
|
|
|
109
140
|
}
|
|
110
141
|
switchToNextProvider() {
|
|
111
142
|
if (this.fallbackProviders.length === 1) {
|
|
112
|
-
this.logger.warn('Will not switch to next provider. No valid backup provider provided.');
|
|
143
|
+
this.logger.warn(this.formatLog('Will not switch to next provider. No valid backup provider provided.'));
|
|
113
144
|
return;
|
|
114
145
|
}
|
|
115
|
-
this.activeFallbackProviderIndex
|
|
116
|
-
this.
|
|
146
|
+
const oldIndex = this.activeFallbackProviderIndex;
|
|
147
|
+
this.activeFallbackProviderIndex =
|
|
148
|
+
(this.activeFallbackProviderIndex + 1) % this.fallbackProviders.length;
|
|
149
|
+
this.logger.log(this.formatLog(`Switched provider: [${oldIndex}] -> [${this.activeFallbackProviderIndex}] (total: ${this.fallbackProviders.length})`));
|
|
117
150
|
}
|
|
118
151
|
isNonRetryableError(error) {
|
|
119
152
|
return (!errors.isEthersServerError(error) &&
|
|
120
153
|
errors.isErrorHasCode(error) &&
|
|
121
154
|
errors.nonRetryableErrors.includes(error.code));
|
|
122
155
|
}
|
|
156
|
+
withTimeout(promise, timeoutMs) {
|
|
157
|
+
return Promise.race([
|
|
158
|
+
promise,
|
|
159
|
+
new Promise((_, reject) => {
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
reject(new requestTimeout_error.RequestTimeoutError(`Request timeout after ${timeoutMs}ms`, timeoutMs));
|
|
162
|
+
}, timeoutMs);
|
|
163
|
+
}),
|
|
164
|
+
]);
|
|
165
|
+
}
|
|
123
166
|
async perform(method, params) {
|
|
124
167
|
const retry = retrier.retrier(this.logger, this.config.maxRetries, this.config.minBackoffMs, this.config.maxBackoffMs, this.config.logRetries, (e) => this.isNonRetryableError(e));
|
|
125
168
|
let attempt = 0;
|
|
@@ -130,9 +173,11 @@ exports.SimpleFallbackJsonRpcBatchProvider = class SimpleFallbackJsonRpcBatchPro
|
|
|
130
173
|
try {
|
|
131
174
|
let performRetryAttempt = 0;
|
|
132
175
|
attempt++;
|
|
176
|
+
// Log which provider we're attempting to use
|
|
177
|
+
this.logger.log(this.formatLog(`Attempting request (attempt ${attempt}/${this.fallbackProviders.length})`, this.activeFallbackProviderIndex));
|
|
133
178
|
// awaiting is extremely important here
|
|
134
179
|
// without it, the error will not be caught in current try-catch scope
|
|
135
|
-
|
|
180
|
+
const result = await retry(() => {
|
|
136
181
|
const provider = this.provider;
|
|
137
182
|
const event = {
|
|
138
183
|
action: 'fallback-provider:request',
|
|
@@ -144,8 +189,16 @@ exports.SimpleFallbackJsonRpcBatchProvider = class SimpleFallbackJsonRpcBatchPro
|
|
|
144
189
|
};
|
|
145
190
|
this._eventEmitter.emit('rpc', event);
|
|
146
191
|
performRetryAttempt++;
|
|
147
|
-
|
|
192
|
+
const performPromise = provider.provider.perform(method, params);
|
|
193
|
+
// Apply timeout if configured
|
|
194
|
+
if (this.config.requestTimeoutMs) {
|
|
195
|
+
return this.withTimeout(performPromise, this.config.requestTimeoutMs);
|
|
196
|
+
}
|
|
197
|
+
return performPromise;
|
|
148
198
|
});
|
|
199
|
+
// Log successful request
|
|
200
|
+
this.logger.log(this.formatLog(`Request successful after ${performRetryAttempt} retry attempt(s)`, this.activeFallbackProviderIndex));
|
|
201
|
+
return result;
|
|
149
202
|
}
|
|
150
203
|
catch (e) {
|
|
151
204
|
this.lastError = e;
|
|
@@ -157,10 +210,22 @@ exports.SimpleFallbackJsonRpcBatchProvider = class SimpleFallbackJsonRpcBatchPro
|
|
|
157
210
|
error: e,
|
|
158
211
|
};
|
|
159
212
|
this._eventEmitter.emit('rpc', event);
|
|
213
|
+
// Log context (label + provider index) synchronously before error object
|
|
214
|
+
// to ensure proper ordering in async logging systems
|
|
215
|
+
this.logger.error(this.formatLog(`Non-retryable error occurred`, this.activeFallbackProviderIndex));
|
|
216
|
+
this.logger.error(e);
|
|
160
217
|
throw e;
|
|
161
218
|
}
|
|
162
|
-
|
|
163
|
-
|
|
219
|
+
// Log context (label + provider index) synchronously before error object
|
|
220
|
+
// to ensure proper ordering in async logging systems
|
|
221
|
+
if (e instanceof requestTimeout_error.RequestTimeoutError) {
|
|
222
|
+
this.logger.error(this.formatLog(`Request timeout after ${e.timeoutMs}ms. Will switch to next provider.`, this.activeFallbackProviderIndex));
|
|
223
|
+
this.logger.error(e);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
this.logger.error(this.formatLog(`Error occurred. Will switch to next provider.`, this.activeFallbackProviderIndex));
|
|
227
|
+
this.logger.error(e);
|
|
228
|
+
}
|
|
164
229
|
// This check is needed to avoid multiple `switchToNextProvider` calls when doing one JSON-RPC batch.
|
|
165
230
|
// This can happen when multiple N calls to `perform` are batched in one JSON-RPC request and
|
|
166
231
|
// that request fails and throws `Error`. This `Error` is bubbled N times to corresponding `perform` calls.
|
|
@@ -218,7 +283,7 @@ exports.SimpleFallbackJsonRpcBatchProvider = class SimpleFallbackJsonRpcBatchPro
|
|
|
218
283
|
if (this.detectNetworkFirstRun) {
|
|
219
284
|
throw new Error(`Fallback provider [${index}] network is different to other provider's networks`);
|
|
220
285
|
}
|
|
221
|
-
this.logger.warn(`Fallback provider [${index}] network is different to other provider's networks`);
|
|
286
|
+
this.logger.warn(this.formatLog(`Fallback provider [${index}] network is different to other provider's networks`));
|
|
222
287
|
}
|
|
223
288
|
}
|
|
224
289
|
else {
|
|
@@ -245,7 +310,7 @@ exports.SimpleFallbackJsonRpcBatchProvider = class SimpleFallbackJsonRpcBatchPro
|
|
|
245
310
|
if (this.resetTimer) {
|
|
246
311
|
clearTimeout(this.resetTimer);
|
|
247
312
|
}
|
|
248
|
-
this.fallbackProviders.forEach((
|
|
313
|
+
this.fallbackProviders.forEach((_, index) => {
|
|
249
314
|
var _a;
|
|
250
315
|
if (!((_a = this.fallbackProviders[index].network) === null || _a === void 0 ? void 0 : _a.chainId)) {
|
|
251
316
|
this.fallbackProviders[index].unreachable = false;
|