Caching network calls #916
Replies: 3 comments 1 reply
-
Thank you for starting this discussion @AndreasGassmann. Adding caching is definitely a good idea. I turned the discussion into an issue: #924 |
Beta Was this translation helpful? Give feedback.
-
@roxaneletourneau I just saw that you also added the Is it possible that this request is either not cached, or maybe because the requests are all started at the same time, they all individually check the cache, which is empty, so it still does all 10 requests? This could be solved by storing the promise in the cache as soon as the first request is started, and if any other request tries to hit the same URL, the cached promise could be returned. (Not sure if you are already doing this). But in any case, great to see those improvements :). |
Beta Was this translation helpful? Give feedback.
-
Looks like my assumption was correct. It's still a problem if multiple requests are done in parallel while the cache is empty. I created a proof of concept class that fixes the problem (at least for the head call, which was the only issue in our case): import { BlockHeaderResponse, defaultRPCOptions, RpcClientCache, RpcClientInterface, RPCOptions } from '@taquito/rpc'
interface CachedDataInterface {
[key: string]: {
handle: Function
response: Promise<any> // CHANGE: Promise
}
}
const defaultTtl = 1000
export class RpcClientPromiseCache extends RpcClientCache {
private rpcClient2: RpcClientInterface
private _cache2: CachedDataInterface = {}
private ttl2: number
constructor(rpcClient: RpcClientInterface, ttl = defaultTtl) {
super(rpcClient, ttl)
this.rpcClient2 = rpcClient
this.ttl2 = ttl
}
private formatCacheKey2(rpcUrl: string, rpcMethodName: string, rpcMethodParams: any[], rpcMethodData?: any) {
let paramsToString = ''
rpcMethodParams.forEach((param) => {
paramsToString = typeof param === 'object' ? paramsToString + JSON.stringify(param) + '/' : paramsToString + param + '/'
})
return rpcMethodData
? `${rpcUrl}/${rpcMethodName}/${paramsToString}/${JSON.stringify(rpcMethodData)}`
: `${rpcUrl}/${rpcMethodName}/${paramsToString}`
}
private has2(key: string) {
return key in this._cache2
}
private get2(key: string) {
return this._cache2[key].response
}
private put2(key: string, response: Promise<any>) {
// CHANGE: "response" parameter is promise
let handle = setTimeout(() => {
return this.remove2(key)
}, this.ttl2)
Object.assign(this._cache2, { [key]: { handle, response } })
}
private remove2(key: string) {
if (key in this._cache2) {
delete this._cache2[key]
}
}
async getBlockHeader({ block }: RPCOptions = defaultRPCOptions): Promise<BlockHeaderResponse> {
const key = this.formatCacheKey2(this.rpcClient2.getRpcUrl(), 'getBlockHeader', [block])
if (this.has2(key)) {
return this.get2(key)
} else {
const response = this.rpcClient2.getBlockHeader({ block }) // CHANGE: do not await request
this.put2(key, response)
return response
}
}
} NOTE: I had to create all those ___2 methods because the original ones were private. |
Beta Was this translation helpful? Give feedback.
-
We are trying to optimise the number of network requests our dapp does. When refreshing a page, we are getting a lot of data from different contracts and storages, which results in a high number of network calls (around 150). Many of them are definitely necessary (eg. getting storage values and bigmap values), but I noticed that the /chains/main/blocks/head/header call is done repeatedly (more than 10 times) during page load. Is it possible to somehow hook into taquito and "cache" those requests? We already cache every ContractAbstraction and storage promise so we can reuse them (and only request the data once), but I don't know how we can prevent the header call. Maybe the easiest will be to just enable caching on the server side.
Beta Was this translation helpful? Give feedback.
All reactions