diff --git a/backend/native/backpack-api/src/routes/graphql/clients/coingecko.ts b/backend/native/backpack-api/src/routes/graphql/clients/coingecko.ts index a5d9853c7..bc473c1a0 100644 --- a/backend/native/backpack-api/src/routes/graphql/clients/coingecko.ts +++ b/backend/native/backpack-api/src/routes/graphql/clients/coingecko.ts @@ -1,9 +1,17 @@ import { RESTDataSource } from "@apollo/datasource-rest"; +import { LRUCache } from "lru-cache"; type CoinGeckoIndexerOptions = { apiKey: string; }; +const IN_MEM_PRICE_DATA_CACHE = new LRUCache({ + allowStale: false, + max: 1000, + ttl: 1000 * 60, // 1 minute TTL + ttlAutopurge: true, +}); + /** * Custom GraphQL REST data source class abstraction for CoinGecko. * @export @@ -22,19 +30,34 @@ export class CoinGeckoIndexer extends RESTDataSource { /** * Fetches the market price data for the argued asset IDs. - * @template I - * @param {I[]} ids - * @returns {Promise>} + * @param {string[]} ids + * @returns {Promise} * @memberof CoinGecko */ async getPrices(ids: string[]): Promise { - const resp: CoinGeckoPriceData[] = await this.get("/", { - params: { - ids: ids.join(","), - }, - }); + const data: CoinGeckoPriceData[] = []; + + const notInCache: string[] = []; + for (const i of ids) { + if (IN_MEM_PRICE_DATA_CACHE.has(i)) { + data.push(IN_MEM_PRICE_DATA_CACHE.get(i)!); + } else { + notInCache.push(i); + } + } + + if (notInCache.length > 0) { + const resp: CoinGeckoPriceData[] = await this.get("/", { + params: { + ids: notInCache.join(","), + }, + }); + + data.push(...resp); + } - return resp.reduce((acc, curr) => { + return data.reduce((acc, curr) => { + IN_MEM_PRICE_DATA_CACHE.set(curr.id, curr); acc[curr.id] = curr; return acc; }, {}); diff --git a/backend/native/backpack-api/src/routes/graphql/clients/helius.ts b/backend/native/backpack-api/src/routes/graphql/clients/helius.ts index 4d3c459bb..83453b691 100644 --- a/backend/native/backpack-api/src/routes/graphql/clients/helius.ts +++ b/backend/native/backpack-api/src/routes/graphql/clients/helius.ts @@ -12,6 +12,7 @@ export const IN_MEM_COLLECTION_DATA_CACHE = new LRUCache< allowStale: false, max: 1000, ttl: 1000 * 60 * 30, // 30 minute TTL + ttlAutopurge: true, }); type HeliusOptions = { diff --git a/backend/native/backpack-api/src/routes/graphql/context.ts b/backend/native/backpack-api/src/routes/graphql/context.ts index a2aa1516f..f4e557740 100644 --- a/backend/native/backpack-api/src/routes/graphql/context.ts +++ b/backend/native/backpack-api/src/routes/graphql/context.ts @@ -20,6 +20,7 @@ const IN_MEM_JWT_CACHE = new LRUCache({ allowStale: false, max: 1000, ttl: 1000 * 60 * 5, // 5 minute TTL + ttlAutopurge: true, }); export interface ApiContext { diff --git a/backend/workers/price-indexer/src/fetched.ts b/backend/workers/price-indexer/src/fetched.ts index c11d4f90b..846fdacc3 100644 --- a/backend/workers/price-indexer/src/fetched.ts +++ b/backend/workers/price-indexer/src/fetched.ts @@ -14,7 +14,7 @@ export const fetchHandler: ExportedHandlerFetchHandler = async ( if (!idsParameter) { return new Response( JSON.stringify({ error: "no asset ids found in url" }), - { status: 400 } + { headers: { "Content-Type": "application/json" }, status: 400 } ); } @@ -24,9 +24,7 @@ export const fetchHandler: ExportedHandlerFetchHandler = async ( ).filter((x) => x) as CoinGeckoPriceData[]; return new Response(JSON.stringify(values), { - headers: { - "Content-Type": "application/json", - }, + headers: { "Content-Type": "application/json" }, status: 200, }); };