Fix: Expire image cache after 90 days

This commit is contained in:
2026-09-10 18:20:48 -07:00
parent ee31ffc2ed
commit 9fae3f0ec9
2 changed files with 8 additions and 4 deletions

View File

@@ -98,9 +98,10 @@ Use images to complement your responses, powered by Brave.
## Caching ## Caching
- Images are cached for **30 days** - Images are cached for **90 days**
- After expiry, the next request triggers a fresh search - After expiry, the next request triggers a fresh search
- Images are stored in their original format as fetched from source - Images are stored in their original format as fetched from source
- A matching R2 lifecycle rule deletes stored objects after 90 days
## Support ## Support
@@ -169,9 +170,11 @@ Fork this repo, connect to Cloudflare Pages, deploy.
**Key:** `<sha256-of-normalized-query>` — derived from query, no lookup needed. Stored with original content type from source. **Key:** `<sha256-of-normalized-query>` — derived from query, no lookup needed. Stored with original content type from source.
Add an object lifecycle rule in **R2 → direct-img-store → Settings** that applies to all prefixes and deletes uploaded objects after **90 days**. This removes expired objects even when their query is never requested again.
### KV: `DIRECT_IMG_CACHE` ### KV: `DIRECT_IMG_CACHE`
**Key:** normalized query (lowercase, trimmed, max 200 chars) → **Value:** `{"t":1719000000,"ct":"image/jpeg"}`**TTL:** 30 days **Key:** normalized query (lowercase, trimmed, max 200 chars) → **Value:** `{"t":1719000000,"ct":"image/jpeg"}`**TTL:** 90 days
### Database: `SurrealDB` (Rate Limiting) ### Database: `SurrealDB` (Rate Limiting)

View File

@@ -1,6 +1,8 @@
import { braveImageSearch } from "./_utils/brave.js"; import { braveImageSearch } from "./_utils/brave.js";
import { bingImageSearchFallback } from "./_utils/bing.js"; import { bingImageSearchFallback } from "./_utils/bing.js";
const TTL_SECONDS = 90 * 24 * 60 * 60;
export async function onRequest(context) { export async function onRequest(context) {
const { request, env, params } = context; const { request, env, params } = context;
const url = new URL(request.url); const url = new URL(request.url);
@@ -28,7 +30,7 @@ export async function onRequest(context) {
const obj = await env.R2_IMAGES.get(r2Key); const obj = await env.R2_IMAGES.get(r2Key);
if (obj) { if (obj) {
const nowSec = Math.floor(Date.now() / 1000); const nowSec = Math.floor(Date.now() / 1000);
const remainingSec = Math.max(0, (cached.t + 5184000) - nowSec); const remainingSec = Math.max(0, (cached.t + TTL_SECONDS) - nowSec);
return new Response(obj.body, { headers: imageHeaders(cached.ct, remainingSec * 1000) }); return new Response(obj.body, { headers: imageHeaders(cached.ct, remainingSec * 1000) });
} }
} }
@@ -184,7 +186,6 @@ export async function onRequest(context) {
const { buffer: imgBuffer, contentType: finalContentType } = imgResult; const { buffer: imgBuffer, contentType: finalContentType } = imgResult;
await env.R2_IMAGES.put(r2Key, imgBuffer, { httpMetadata: { contentType: finalContentType } }); await env.R2_IMAGES.put(r2Key, imgBuffer, { httpMetadata: { contentType: finalContentType } });
const TTL_SECONDS = 5184000;
await env.DIRECT_IMG_CACHE.put(cacheKey, JSON.stringify({ t: Math.floor(Date.now() / 1000), ct: finalContentType }), { expirationTtl: TTL_SECONDS }); await env.DIRECT_IMG_CACHE.put(cacheKey, JSON.stringify({ t: Math.floor(Date.now() / 1000), ct: finalContentType }), { expirationTtl: TTL_SECONDS });
return new Response(imgBuffer, { headers: imageHeaders(finalContentType, TTL_SECONDS * 1000) }); return new Response(imgBuffer, { headers: imageHeaders(finalContentType, TTL_SECONDS * 1000) });