Skip to content

Commit 1e46f3c

Browse files
committed
change file based to in memory cache
1 parent e8af572 commit 1e46f3c

File tree

8 files changed

+77
-79
lines changed

8 files changed

+77
-79
lines changed

src/lib/utils/data/cacheAsyncFn.ts

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,53 @@
1-
import fs from "fs"
2-
import path from "path"
3-
4-
const CACHE_FILE_DIR = path.resolve(".next/cache")
5-
61
/**
7-
* Caches the result of an asynchronous function to avoid multiple calls during build time.
8-
* This helps prevent hitting external API rate limits by storing the result in a file.
2+
* Caches the result of an asynchronous function in memory to avoid multiple calls.
3+
* This helps prevent hitting external API rate limits by storing the result in memory.
94
*
105
* @param key A unique identifier for the cached function result
116
* @param fn The asynchronous function to be cached
127
* @param options Optional parameters to configure cache behavior
13-
* @returns A new function that returns the cached result or executes the original function if the cache is invalid
8+
* @param options.cacheTimeout The duration in milliseconds for which the cache remains valid
9+
* @returns A new function that returns the cached result or executes the original function if the cache is expired
1410
*
1511
* @example
16-
* const cachedFetch = cacheAsyncFn('uniqueKey', fetchSomething);
12+
* const cachedFetch = cacheAsyncFn('uniqueKey', fetchSomething, { cacheTimeout: 60000 });
1713
*
1814
* await cachedFetch(); // Fetches and caches the data
19-
* await cachedFetch(); // Returns the cached data without re-fetching
20-
*
21-
* @note The cache is stored in the '.next/cache' directory and expires after the `cacheTimeout`
15+
* await cachedFetch(); // Returns the cached data
2216
*/
2317

18+
// In-memory cache object
19+
const memoryCache: Record<string, { value: unknown; timestamp: number }> = {}
20+
2421
export function cacheAsyncFn<T>(
2522
key: string,
2623
fn: () => Promise<T>,
2724
options?: { cacheTimeout?: number }
2825
) {
29-
const cacheFilePath = path.resolve(CACHE_FILE_DIR, `${key}.json`)
30-
3126
return async (): Promise<T> => {
32-
let value: T | undefined
27+
const now = Date.now()
28+
const cachedItem = memoryCache[key]
3329

34-
// Check if cache file exists
35-
if (fs.existsSync(cacheFilePath)) {
36-
const fileStats = fs.statSync(cacheFilePath)
37-
const now = Date.now()
38-
const cacheAge = now - new Date(fileStats.mtime).getTime()
30+
// Check if cache exists and is not expired
31+
if (cachedItem) {
32+
const cacheAge = now - cachedItem.timestamp
3933
const isCacheExpired =
4034
options?.cacheTimeout && cacheAge > options.cacheTimeout
4135

42-
// Invalidate cache if it's too old
43-
if (isCacheExpired) {
44-
// Remove stale cache
45-
fs.unlinkSync(cacheFilePath)
46-
console.log("Stale cache removed", key)
47-
} else {
48-
// Cache hit
49-
const cachedData = fs.readFileSync(cacheFilePath, "utf-8")
50-
value = JSON.parse(cachedData)
36+
if (!isCacheExpired) {
5137
console.log("Cache hit", key)
38+
return cachedItem.value as T
5239
}
40+
console.log("Cache expired", key)
5341
}
5442

55-
// If no cached data, fetch fresh data
56-
if (!value) {
57-
console.log("Running function for the first time", key)
58-
value = await fn()
59-
console.log("Function ran and cached", key)
60-
61-
// Ensure cache folder exists
62-
fs.mkdirSync(CACHE_FILE_DIR, { recursive: true })
43+
// Fetch fresh data
44+
console.log("Running function", key)
45+
const value = await fn()
6346

64-
// Write data to cache file
65-
fs.writeFileSync(cacheFilePath, JSON.stringify(value), "utf-8")
66-
console.log("Function cached", key)
67-
}
47+
// Store in memory cache
48+
memoryCache[key] = { value: value, timestamp: now }
49+
console.log("Function result cached", key)
6850

69-
return value!
51+
return value as T
7052
}
7153
}

src/lib/utils/data/dataLoader.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,36 @@ const USE_MOCK_DATA = process.env.USE_MOCK_DATA === "true"
66
type DataLoaderFunction<T> = () => Promise<T>
77

88
/**
9-
* Loads data from multiple asynchronous functions and caches the results.
9+
* Creates a function that loads data from multiple asynchronous functions and caches the results.
1010
*
1111
* @param loaders An array of tuples, each containing a unique identifier and the asynchronous function to be cached
12-
* @returns A promise that resolves to an array of the results from the cached functions
12+
* @param cacheTimeout Optional cache timeout in milliseconds
13+
* @returns A function that, when called, executes the loaders and returns a promise with the results
1314
*
1415
* @example
15-
* const [ethPrice, totalEthStaked, totalValueLocked] = await dataLoader([
16+
* const loadData = dataLoader([
1617
* ['ethPrice', fetchEthPrice],
1718
* ['totalEthStaked', fetchTotalEthStaked],
1819
* ['totalValueLocked', fetchTotalValueLocked],
1920
* ]);
21+
*
22+
* const [ethPrice, totalEthStaked, totalValueLocked] = await loadData();
2023
*/
2124

22-
export async function dataLoader<T extends unknown[]>(
25+
export function dataLoader<T extends unknown[]>(
2326
loaders: {
2427
[K in keyof T]: [string, DataLoaderFunction<T[K]>]
2528
},
2629
cacheTimeout?: number
27-
): Promise<T> {
30+
): () => Promise<T> {
2831
const cachedLoaders = loaders.map(([key, loader]) => {
2932
const cachedLoader = cacheAsyncFn(key, loader, {
3033
cacheTimeout,
3134
})
3235
return async () => {
3336
try {
3437
if (USE_MOCK_DATA) {
38+
console.log("Using mock data for", key)
3539
return await loadMockData(key)
3640
}
3741

@@ -43,6 +47,8 @@ export async function dataLoader<T extends unknown[]>(
4347
}
4448
})
4549

46-
const results = await Promise.all(cachedLoaders.map((loader) => loader()))
47-
return results as T
50+
return async () => {
51+
const results = await Promise.all(cachedLoaders.map((loader) => loader()))
52+
return results as T
53+
}
4854
}

src/pages/[...slug].tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ type Props = Omit<Parameters<LayoutMappingType[Layout]>[0], "children"> &
116116

117117
const commitHistoryCache: CommitHistory = {}
118118

119+
const loadData = dataLoader([["gfissues", fetchGFIs]])
120+
119121
export const getStaticProps = (async (context) => {
120122
const params = context.params!
121123
const { locale } = context
@@ -194,7 +196,7 @@ export const getStaticProps = (async (context) => {
194196
lastDeployDate
195197
)
196198

197-
const [gfissues] = await dataLoader([["gfissues", fetchGFIs]])
199+
const [gfissues] = await loadData()
198200

199201
return {
200202
props: {

src/pages/developers/local-environment.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ const Column = ({ children }: ChildOnlyProp) => {
5353
)
5454
}
5555

56+
const loadData = dataLoader([
57+
["frameworksListData", getLocalEnvironmentFrameworkData],
58+
])
59+
5660
type Props = BasePageProps & {
5761
frameworksList: Framework[]
5862
}
@@ -64,9 +68,7 @@ export const getStaticProps = (async ({ locale }) => {
6468

6569
const contentNotTranslated = !existsNamespace(locale!, requiredNamespaces[2])
6670

67-
const [frameworksListData] = await dataLoader([
68-
["frameworksListData", getLocalEnvironmentFrameworkData],
69-
])
71+
const [frameworksListData] = await loadData()
7072

7173
const lastDeployDate = getLastDeployDate()
7274
const lastDeployLocaleTimestamp = getLocaleTimestamp(

src/pages/index.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,19 @@ type Props = BasePageProps & {
121121
// In seconds
122122
const REVALIDATE_TIME = BASE_TIME_UNIT * 24
123123

124+
const loadData = dataLoader(
125+
[
126+
["ethPrice", fetchEthPrice],
127+
["totalEthStaked", fetchTotalEthStaked],
128+
["totalValueLocked", fetchTotalValueLocked],
129+
["growThePieData", fetchGrowThePie],
130+
["communityEvents", fetchCommunityEvents],
131+
["attestantPosts", fetchAttestantPosts],
132+
["rssData", fetchXmlBlogFeeds],
133+
],
134+
REVALIDATE_TIME * 1000
135+
)
136+
124137
export const getStaticProps = (async ({ locale }) => {
125138
const [
126139
ethPrice,
@@ -130,18 +143,7 @@ export const getStaticProps = (async ({ locale }) => {
130143
communityEvents,
131144
attestantPosts,
132145
xmlBlogs,
133-
] = await dataLoader(
134-
[
135-
["ethPrice", fetchEthPrice],
136-
["totalEthStaked", fetchTotalEthStaked],
137-
["totalValueLocked", fetchTotalValueLocked],
138-
["growThePieData", fetchGrowThePie],
139-
["communityEvents", fetchCommunityEvents],
140-
["attestantPosts", fetchAttestantPosts],
141-
["rssData", fetchXmlBlogFeeds],
142-
],
143-
REVALIDATE_TIME * 1000
144-
)
146+
] = await loadData()
145147

146148
const metricResults: AllMetricData = {
147149
ethPrice,

src/pages/stablecoins.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ type Props = BasePageProps & {
9393
// In seconds
9494
const REVALIDATE_TIME = BASE_TIME_UNIT * 24 * 7
9595

96+
const loadData = dataLoader<[EthereumDataResponse, StablecoinDataResponse]>(
97+
[
98+
["ethereumEcosystemData", fetchEthereumEcosystemData],
99+
["ethereumStablecoinsData", fetchEthereumStablecoinsData],
100+
],
101+
REVALIDATE_TIME * 1000
102+
)
103+
96104
export const getStaticProps = (async ({ locale }) => {
97105
const lastDeployDate = getLastDeployDate()
98106
const lastDeployLocaleTimestamp = getLocaleTimestamp(
@@ -138,15 +146,7 @@ export const getStaticProps = (async ({ locale }) => {
138146
}
139147

140148
try {
141-
const [ethereumEcosystemData, stablecoinsData] = await dataLoader<
142-
[EthereumDataResponse, StablecoinDataResponse]
143-
>(
144-
[
145-
["ethereumEcosystemData", fetchEthereumEcosystemData],
146-
["ethereumStablecoinsData", fetchEthereumStablecoinsData],
147-
],
148-
REVALIDATE_TIME * 1000
149-
)
149+
const [ethereumEcosystemData, stablecoinsData] = await loadData()
150150

151151
// Get the intersection of stablecoins and Ethereum tokens to only have a list of data for stablecoins in the Ethereum ecosystem
152152
const ethereumStablecoinData = stablecoinsData.filter(

src/pages/staking/index.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ type Props = BasePageProps & {
156156
// In seconds
157157
const REVALIDATE_TIME = BASE_TIME_UNIT * 24
158158

159+
const loadData = dataLoader(
160+
[["stakingStatsData", fetchBeaconchainData]],
161+
REVALIDATE_TIME * 1000
162+
)
163+
159164
export const getStaticProps = (async ({ locale }) => {
160165
const lastDeployDate = getLastDeployDate()
161166
const lastDeployLocaleTimestamp = getLocaleTimestamp(
@@ -167,10 +172,7 @@ export const getStaticProps = (async ({ locale }) => {
167172

168173
const contentNotTranslated = !existsNamespace(locale!, requiredNamespaces[2])
169174

170-
const [data] = await dataLoader(
171-
[["stakingStatsData", fetchBeaconchainData]],
172-
REVALIDATE_TIME * 1000
173-
)
175+
const [data] = await loadData()
174176

175177
return {
176178
props: {

src/pages/what-is-ethereum.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,10 @@ type Props = BasePageProps & {
176176
data: MetricReturnData
177177
}
178178

179+
const loadData = dataLoader([["growThePieData", fetchGrowThePie]])
180+
179181
export const getStaticProps = (async ({ locale }) => {
180-
const [data] = await dataLoader([["growThePieData", fetchGrowThePie]])
182+
const [data] = await loadData()
181183

182184
const lastDeployDate = getLastDeployDate()
183185
const lastDeployLocaleTimestamp = getLocaleTimestamp(

0 commit comments

Comments
 (0)