Add option to adjust perform cache timeout in AbstractProvider.

This commit is contained in:
Richard Moore 2023-06-13 21:40:26 -04:00
parent 84375be92d
commit de0f5189f6
2 changed files with 42 additions and 5 deletions

@ -398,6 +398,24 @@ type _PerformAccountRequest = {
method: "getStorage", position: bigint method: "getStorage", position: bigint
} }
/**
* Options for configuring some internal aspects of an [[AbstractProvider]].
*
* **``cacheTimeout``** - how long to cache a low-level ``_perform``
* for, based on input parameters. This reduces the number of calls
* to getChainId and getBlockNumber, but may break test chains which
* can perform operations (internally) synchronously. Use ``-1`` to
* disable, ``0`` will only buffer within the same event loop and
* any other value is in ms. (default: ``250``)
*/
export type AbstractProviderOptions = {
cacheTimeout?: number;
};
const defaultOptions = {
cacheTimeout: 250
};
type CcipArgs = { type CcipArgs = {
sender: string; sender: string;
urls: Array<string>; urls: Array<string>;
@ -436,12 +454,15 @@ export class AbstractProvider implements Provider {
#disableCcipRead: boolean; #disableCcipRead: boolean;
#options: Required<AbstractProviderOptions>;
/** /**
* Create a new **AbstractProvider** connected to %%network%%, or * Create a new **AbstractProvider** connected to %%network%%, or
* use the various network detection capabilities to discover the * use the various network detection capabilities to discover the
* [[Network]] if necessary. * [[Network]] if necessary.
*/ */
constructor(_network?: "any" | Networkish) { constructor(_network?: "any" | Networkish, options?: AbstractProviderOptions) {
this.#options = Object.assign({ }, defaultOptions, options || { });
if (_network === "any") { if (_network === "any") {
this.#anyNetwork = true; this.#anyNetwork = true;
@ -512,19 +533,25 @@ export class AbstractProvider implements Provider {
// Shares multiple identical requests made during the same 250ms // Shares multiple identical requests made during the same 250ms
async #perform<T = any>(req: PerformActionRequest): Promise<T> { async #perform<T = any>(req: PerformActionRequest): Promise<T> {
const timeout = this.#options.cacheTimeout;
// Caching disabled
if (timeout < 0) { return await this._perform(req); }
// Create a tag // Create a tag
const tag = getTag(req.method, req); const tag = getTag(req.method, req);
let perform = this.#performCache.get(tag); let perform = this.#performCache.get(tag);
if (!perform) { if (!perform) {
perform = this._perform(req); perform = this._perform(req);
this.#performCache.set(tag, perform); this.#performCache.set(tag, perform);
setTimeout(() => { setTimeout(() => {
if (this.#performCache.get(tag) === perform) { if (this.#performCache.get(tag) === perform) {
this.#performCache.delete(tag); this.#performCache.delete(tag);
} }
}, 250); }, timeout);
} }
return await perform; return await perform;

@ -34,7 +34,7 @@ import { PollingEventSubscriber } from "./subscriber-polling.js";
import type { TypedDataDomain, TypedDataField } from "../hash/index.js"; import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
import type { TransactionLike } from "../transaction/index.js"; import type { TransactionLike } from "../transaction/index.js";
import type { PerformActionRequest, Subscriber, Subscription } from "./abstract-provider.js"; import type { AbstractProviderOptions, PerformActionRequest, Subscriber, Subscription } from "./abstract-provider.js";
import type { Networkish } from "./network.js"; import type { Networkish } from "./network.js";
import type { Provider, TransactionRequest, TransactionResponse } from "./provider.js"; import type { Provider, TransactionRequest, TransactionResponse } from "./provider.js";
import type { Signer } from "./signer.js"; import type { Signer } from "./signer.js";
@ -185,6 +185,8 @@ export type DebugEventJsonRpcApiProvider = {
* *
* **``batchMaxCount``** - maximum number of requests to allow in a batch. * **``batchMaxCount``** - maximum number of requests to allow in a batch.
* If ``batchMaxCount = 1``, then batching is disabled. (default: ``100``) * If ``batchMaxCount = 1``, then batching is disabled. (default: ``100``)
*
* **``cacheTimeout``** - passed as [[AbstractProviderOptions]].
*/ */
export type JsonRpcApiProviderOptions = { export type JsonRpcApiProviderOptions = {
polling?: boolean; polling?: boolean;
@ -192,6 +194,8 @@ export type JsonRpcApiProviderOptions = {
batchStallTime?: number; batchStallTime?: number;
batchMaxSize?: number; batchMaxSize?: number;
batchMaxCount?: number; batchMaxCount?: number;
cacheTimeout?: number;
}; };
const defaultOptions = { const defaultOptions = {
@ -200,7 +204,9 @@ const defaultOptions = {
batchStallTime: 10, // 10ms batchStallTime: 10, // 10ms
batchMaxSize: (1 << 20), // 1Mb batchMaxSize: (1 << 20), // 1Mb
batchMaxCount: 100 // 100 requests batchMaxCount: 100, // 100 requests
cacheTimeout: 250
} }
/** /**
@ -537,7 +543,11 @@ export abstract class JsonRpcApiProvider extends AbstractProvider {
} }
constructor(network?: Networkish, options?: JsonRpcApiProviderOptions) { constructor(network?: Networkish, options?: JsonRpcApiProviderOptions) {
super(network); const superOptions: AbstractProviderOptions = { };
if (options && options.cacheTimeout != null) {
superOptions.cacheTimeout = options.cacheTimeout;
}
super(network, superOptions);
this.#nextId = 1; this.#nextId = 1;
this.#options = Object.assign({ }, defaultOptions, options || { }); this.#options = Object.assign({ }, defaultOptions, options || { });