For Workers & Pages, what is the name of the domain?
What is the issue or error you’re encountering
Cloudflare KV Caching API - High Read Usage Despite Cache Implementation
What steps have you taken to resolve the issue?
I’m using Cloudflare’s Caching API to optimize my KV read usage. My goal is to cache the KV data for 1 minute and keep the reads below 2000 per day. However, I’m seeing around 38,000 KV reads daily. I suspect I might be using the Caching API incorrectly.
Here’s my setup:
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
let cachedSubdomains = new Set();
let lastFetchTime = 0;
export default {
async fetch(request, env) {
const url = new URL(request.url);
const subdomain = url.hostname.split(“.”)[0];
console.log("Checking cached subdomains:", cachedSubdomains, "Subdomain:", subdomain);
// Refresh cache if empty or expired
if (cachedSubdomains.size === 0 || Date.now() - lastFetchTime > CACHE_DURATION) {
try {
cachedSubdomains = await updateCachedSubdomains(env);
lastFetchTime = Date.now();
console.log("Updated cached subdomains:", cachedSubdomains);
} catch (err) {
console.error("Cache update failed:", err);
if (cachedSubdomains.size === 0) {
return redirectToNA();
}
}
}
// If the subdomain exists, proxy the request
if (cachedSubdomains.has(subdomain)) {
return proxyRequest(request, url);
}
console.log("Subdomain not found, redirecting:", subdomain);
return redirectToNA();
},
};
// Function to update cached subdomains
async function updateCachedSubdomains(env) {
const cache = caches.default;
const cacheKey = “https://subdomains-cache.example.com”;
// Explicitly delete cache before fetching from KV
await cache.delete(cacheKey);
console.log(“Cache deleted, fetching from KV…”);
// Fetch from KV
const kvData = await env.SUBDOMAINS.get(“example.com”);
if (!kvData) {
console.warn(“KV returned null, falling back to empty set.”);
return new Set();
}
let subdomains;
try {
const parsedKV = JSON.parse(kvData);
subdomains = new Set(JSON.parse(parsedKV.value || “”));
} catch (err) {
console.error(“Error parsing KV data:”, err);
return new Set();
}
console.log(“Fetched from KV:”, subdomains);
// Store in Cache API (if needed)
const response = new Response(JSON.stringify([…subdomains]), {
headers: {
“Cache-Control”: “max-age=60”, // Cache for 1 minute
“Content-Type”: “application/json”
}
});
await cache.put(cacheKey, response);
return subdomains;
}
// Function to proxy the request
async function proxyRequest(request, url) {
const originResponse = await fetch(
new Request(
https://example-proxy.example.workers.dev${url.pathname}${url.search}
,
request
)
);
// Clone response and modify headers
const newHeaders = new Headers(originResponse.headers);
newHeaders.set(“Cache-Control”, “no-store, no-cache, must-revalidate, proxy-revalidate”);
newHeaders.set(“Pragma”, “no-cache”);
newHeaders.set(“Expires”, “0”);
return new Response(originResponse.body, {
status: originResponse.status,
statusText: originResponse.statusText,
headers: newHeaders,
});
}
// Function to handle redirection with CORS headers
function redirectToNA() {
return new Response(null, {
status: 307,
headers: {
“Location”: “https://na.example.com/”,
“Access-Control-Allow-Origin”: “*”, // Fix CORS issues
“Access-Control-Allow-Methods”: “GET, OPTIONS”,
“Access-Control-Allow-Headers”: “Content-Type”
}
});
}