From 448c1ce217c6ba435aa7579195ddb6f6dc0e04f3 Mon Sep 17 00:00:00 2001 From: Valentin Fernandez <33705477+valentinfernandez1@users.noreply.github.com> Date: Thu, 29 May 2025 13:38:11 -0300 Subject: [PATCH] Initialize RpcCore with configured ttl (#6160) * Initialize RpcCore with configured ttl * lint --- packages/api/src/base/Decorate.ts | 1 + packages/rpc-core/src/bundle.ts | 5 +++-- packages/rpc-provider/src/http/index.ts | 16 ++++++++++++++-- packages/rpc-provider/src/lru.ts | 12 ++++++++---- packages/rpc-provider/src/types.ts | 2 ++ packages/rpc-provider/src/ws/index.ts | 15 +++++++++++++-- 6 files changed, 41 insertions(+), 10 deletions(-) diff --git a/packages/api/src/base/Decorate.ts b/packages/api/src/base/Decorate.ts index 0cf91303b5..70015a4c88 100644 --- a/packages/api/src/base/Decorate.ts +++ b/packages/api/src/base/Decorate.ts @@ -154,6 +154,7 @@ export abstract class Decorate extends Events { isPedantic: this._options.isPedantic, provider, rpcCacheCapacity: this._options.rpcCacheCapacity, + ttl: this._options.provider?.ttl, userRpc: this._options.rpc }) as (RpcCore & RpcInterface); this._isConnected = new BehaviorSubject(this._rpcCore.provider.isConnected); diff --git a/packages/rpc-core/src/bundle.ts b/packages/rpc-core/src/bundle.ts index dcc37a0d7e..b6c03022ec 100644 --- a/packages/rpc-core/src/bundle.ts +++ b/packages/rpc-core/src/bundle.ts @@ -37,6 +37,7 @@ interface Options { * Custom size of the rpc LRUCache capacity. Defaults to `RPC_CORE_DEFAULT_CAPACITY` (1024 * 10 * 10) */ rpcCacheCapacity?: number; + ttl?: number | null; userRpc?: Record>; } @@ -117,7 +118,7 @@ export class RpcCore { * @param {ProviderInterface} options.provider An API provider using any of the supported providers (HTTP, SC or WebSocket) * @param {number} [options.rpcCacheCapacity] Custom size of the rpc LRUCache capacity. Defaults to `RPC_CORE_DEFAULT_CAPACITY` (1024 * 10 * 10) */ - constructor (instanceId: string, registry: Registry, { isPedantic = true, provider, rpcCacheCapacity, userRpc = {} }: Options) { + constructor (instanceId: string, registry: Registry, { isPedantic = true, provider, rpcCacheCapacity, ttl, userRpc = {} }: Options) { if (!provider || !isFunction(provider.send)) { throw new Error('Expected Provider to API create'); } @@ -131,7 +132,7 @@ export class RpcCore { // these are the base keys (i.e. part of jsonrpc) this.sections.push(...sectionNames); - this.#storageCache = new LRUCache(rpcCacheCapacity || RPC_CORE_DEFAULT_CAPACITY); + this.#storageCache = new LRUCache(rpcCacheCapacity || RPC_CORE_DEFAULT_CAPACITY, ttl); // decorate all interfaces, defined and user on this instance this.addUserInterfaces(userRpc); } diff --git a/packages/rpc-provider/src/http/index.ts b/packages/rpc-provider/src/http/index.ts index 83bb868909..f3a7b89310 100644 --- a/packages/rpc-provider/src/http/index.ts +++ b/packages/rpc-provider/src/http/index.ts @@ -42,6 +42,7 @@ export class HttpProvider implements ProviderInterface { readonly #endpoint: string; readonly #headers: Record; readonly #stats: ProviderStats; + readonly #ttl: number | null | undefined; /** * @param {string} endpoint The endpoint url starting with http:// @@ -49,7 +50,7 @@ export class HttpProvider implements ProviderInterface { * @param {number} [cacheCapacity] Custom size of the HttpProvider LRUCache. Defaults to `DEFAULT_CAPACITY` (1024) * @param {number} [cacheTtl] Custom TTL of the HttpProvider LRUCache. Determines how long an object can live in the cache. Defaults to `DEFAULT_TTL` (30000) */ - constructor (endpoint: string = defaults.HTTP_URL, headers: Record = {}, cacheCapacity?: number, cacheTtl?: number) { + constructor (endpoint: string = defaults.HTTP_URL, headers: Record = {}, cacheCapacity?: number, cacheTtl?: number | null) { if (!/^(https|http):\/\//.test(endpoint)) { throw new Error(`Endpoint should start with 'http://' or 'https://', received '${endpoint}'`); } @@ -57,9 +58,13 @@ export class HttpProvider implements ProviderInterface { this.#coder = new RpcCoder(); this.#endpoint = endpoint; this.#headers = headers; - this.#callCache = new LRUCache(cacheCapacity === 0 ? 0 : cacheCapacity || DEFAULT_CAPACITY, cacheTtl || DEFAULT_TTL); this.#cacheCapacity = cacheCapacity === 0 ? 0 : cacheCapacity || DEFAULT_CAPACITY; + const ttl = cacheTtl === undefined ? DEFAULT_TTL : cacheTtl; + + this.#callCache = new LRUCache(cacheCapacity === 0 ? 0 : cacheCapacity || DEFAULT_CAPACITY, ttl); + this.#ttl = cacheTtl; + this.#stats = { active: { requests: 0, subscriptions: 0 }, total: { bytesRecv: 0, bytesSent: 0, cached: 0, errors: 0, requests: 0, subscriptions: 0, timeout: 0 } @@ -101,6 +106,13 @@ export class HttpProvider implements ProviderInterface { return this.#stats; } + /** + * @description Returns the connection stats + */ + public get ttl (): number | null | undefined { + return this.#ttl; + } + /** * @summary `true` when this provider supports clone() */ diff --git a/packages/rpc-provider/src/lru.ts b/packages/rpc-provider/src/lru.ts index 5f8b49ab0b..3c644be548 100644 --- a/packages/rpc-provider/src/lru.ts +++ b/packages/rpc-provider/src/lru.ts @@ -8,6 +8,10 @@ export const DEFAULT_CAPACITY = 1024; export const DEFAULT_TTL = 30000; +// If the user decides to disable the TTL we set the value +// to a very high number (A year = 365 * 24 * 60 * 60 * 1000). +const DISABLED_TTL = 31_536_000_000; + class LRUNode { readonly key: string; #expires: number; @@ -47,13 +51,13 @@ export class LRUCache { readonly #ttl: number; - constructor (capacity = DEFAULT_CAPACITY, ttl = DEFAULT_TTL) { + constructor (capacity = DEFAULT_CAPACITY, ttl: number | null = DEFAULT_TTL) { this.capacity = capacity; - this.#ttl = ttl; - this.#head = this.#tail = new LRUNode('', ttl); + ttl ? this.#ttl = ttl : this.#ttl = DISABLED_TTL; + this.#head = this.#tail = new LRUNode('', this.#ttl); } - get ttl (): number { + get ttl (): number | null { return this.#ttl; } diff --git a/packages/rpc-provider/src/types.ts b/packages/rpc-provider/src/types.ts index 8307ba5e1e..ba8540e996 100644 --- a/packages/rpc-provider/src/types.ts +++ b/packages/rpc-provider/src/types.ts @@ -57,6 +57,8 @@ export interface ProviderInterface { readonly isConnected: boolean; /** (optional) stats for the provider with connections/bytes */ readonly stats?: ProviderStats; + /** (optional) stats for the provider with connections/bytes */ + readonly ttl?: number | null; clone (): ProviderInterface; connect (): Promise; diff --git a/packages/rpc-provider/src/ws/index.ts b/packages/rpc-provider/src/ws/index.ts index ffc3724d7a..ffbb1dd481 100644 --- a/packages/rpc-provider/src/ws/index.ts +++ b/packages/rpc-provider/src/ws/index.ts @@ -94,6 +94,7 @@ export class WsProvider implements ProviderInterface { readonly #stats: ProviderStats; readonly #waitingForId: Record> = {}; readonly #cacheCapacity: number; + readonly #ttl: number | null | undefined; #autoConnectMs: number; #endpointIndex: number; @@ -112,7 +113,7 @@ export class WsProvider implements ProviderInterface { * @param {number} [cacheCapacity] Custom size of the WsProvider LRUCache. Defaults to `DEFAULT_CAPACITY` (1024) * @param {number} [cacheTtl] Custom TTL of the WsProvider LRUCache. Determines how long an object can live in the cache. Defaults to DEFAULT_TTL` (30000) */ - constructor (endpoint: string | string[] = defaults.WS_URL, autoConnectMs: number | false = RETRY_DELAY, headers: Record = {}, timeout?: number, cacheCapacity?: number, cacheTtl?: number) { + constructor (endpoint: string | string[] = defaults.WS_URL, autoConnectMs: number | false = RETRY_DELAY, headers: Record = {}, timeout?: number, cacheCapacity?: number, cacheTtl?: number | null) { const endpoints = Array.isArray(endpoint) ? endpoint : [endpoint]; @@ -126,7 +127,10 @@ export class WsProvider implements ProviderInterface { throw new Error(`Endpoint should start with 'ws://', received '${endpoint}'`); } }); - this.#callCache = new LRUCache(cacheCapacity || DEFAULT_CAPACITY, cacheTtl || DEFAULT_TTL); + const ttl = cacheTtl === undefined ? DEFAULT_TTL : cacheTtl; + + this.#callCache = new LRUCache(cacheCapacity === 0 ? 0 : cacheCapacity || DEFAULT_CAPACITY, ttl); + this.#ttl = cacheTtl; this.#cacheCapacity = cacheCapacity || DEFAULT_CAPACITY; this.#eventemitter = new EventEmitter(); this.#autoConnectMs = autoConnectMs || 0; @@ -288,6 +292,13 @@ export class WsProvider implements ProviderInterface { }; } + /** + * @description Returns the connection stats + */ + public get ttl (): number | null | undefined { + return this.#ttl; + } + public get endpointStats (): EndpointStats { return this.#endpointStats; }