Skip to content

Commit 3748238

Browse files
arcestiaSkiddle-Git
authored andcommitted
Minimize consume of KV read, write & delete operation
Fixes #1 Minimize KV read, write, and delete operation consumption to make it more suitable for the free plan. * **In-memory cache**: Add `statsCache` and `rateLimitCache` to store stats and rate limit data in memory. * **Initialize stats**: Cache stats in memory to avoid repeated KV reads in the `initializeStats` function. * **Stats middleware**: Batch updates to the stats and write them to the KV store periodically instead of on every request. * **Rate limiting middleware**: Cache rate limit data in memory to avoid repeated KV reads and writes in the `checkRateLimit` function. Use a single KV read and write operation per request. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/arcestia/domainchecker/issues/1?shareId=XXXX-XXXX-XXXX-XXXX).
1 parent 7072e7c commit 3748238

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

src/index.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,19 @@ const RATE_LIMIT = {
3333
WINDOW_MINUTES: 10
3434
}
3535

36+
// In-memory cache
37+
let statsCache: StatsData | null = null
38+
let rateLimitCache: { [key: string]: RateLimitData } = {}
39+
3640
// Middleware
3741
app.use('*', logger())
3842
app.use('*', cors())
3943

4044
// Initialize stats if not exists
4145
async function initializeStats(c: Context<Bindings>): Promise<StatsData> {
46+
if (statsCache) {
47+
return statsCache
48+
}
4249
const stats = await c.env.STATS_STORE.get('global_stats')
4350
if (!stats) {
4451
const initialStats: StatsData = {
@@ -51,35 +58,44 @@ async function initializeStats(c: Context<Bindings>): Promise<StatsData> {
5158
lastReset: Date.now()
5259
}
5360
await c.env.STATS_STORE.put('global_stats', JSON.stringify(initialStats))
61+
statsCache = initialStats
5462
return initialStats
5563
}
56-
return JSON.parse(stats)
64+
statsCache = JSON.parse(stats)
65+
return statsCache
5766
}
5867

5968
// Stats middleware
6069
app.use('*', async (c, next) => {
6170
if (c.req.method === 'POST' && c.req.path === '/check') {
6271
const stats = await initializeStats(c)
6372
stats.totalRequests++
64-
await c.env.STATS_STORE.put('global_stats', JSON.stringify(stats))
73+
statsCache = stats
6574
}
6675
await next()
6776
})
6877

78+
// Periodically write stats to KV store
79+
setInterval(async () => {
80+
if (statsCache) {
81+
await c.env.STATS_STORE.put('global_stats', JSON.stringify(statsCache))
82+
}
83+
}, 60000) // Every 60 seconds
84+
6985
// Rate limiting middleware
7086
async function checkRateLimit(c: Context<Bindings>, ip: string, domainCount: number): Promise<{ allowed: boolean, remaining: number, resetTime?: Date }> {
7187
const key = `rate_limit:${ip}`
7288
const now = Date.now()
7389
const windowStart = now - (RATE_LIMIT.WINDOW_MINUTES * 60 * 1000)
7490

75-
const stored = await c.env.RATE_LIMIT_STORE.get(key)
76-
let usage: RateLimitData | null = stored ? JSON.parse(stored) : null
91+
let usage: RateLimitData | null = rateLimitCache[key] || null
7792

7893
if (!usage || usage.timestamp < windowStart) {
7994
usage = {
8095
count: domainCount,
8196
timestamp: now
8297
}
98+
rateLimitCache[key] = usage
8399
await c.env.RATE_LIMIT_STORE.put(key, JSON.stringify(usage), {
84100
expirationTtl: RATE_LIMIT.WINDOW_MINUTES * 60 // TTL in seconds
85101
})
@@ -104,6 +120,7 @@ async function checkRateLimit(c: Context<Bindings>, ip: string, domainCount: num
104120
count: totalCount,
105121
timestamp: usage.timestamp
106122
}
123+
rateLimitCache[key] = usage
107124
await c.env.RATE_LIMIT_STORE.put(key, JSON.stringify(usage), {
108125
expirationTtl: RATE_LIMIT.WINDOW_MINUTES * 60 // TTL in seconds
109126
})
@@ -554,7 +571,7 @@ app.post('/check', async (c: Context<Bindings>) => {
554571
})
555572

556573
// Save updated stats
557-
await c.env.STATS_STORE.put('global_stats', JSON.stringify(stats))
574+
statsCache = stats
558575

559576
return c.json({
560577
domains: results,

0 commit comments

Comments
 (0)