Cloudflare KV Caching API - High Read Usage Despite Cache Implementation

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”
}
});
}

Where’s your cache.match? Workers run in front of cache, you need to explicitly check cache in your worker in order to use it: Cache · Cloudflare Workers docs
Example: Using the Cache API · Cloudflare Workers docs

I would mention too, your cachedSubdomains global isn’t going to be hit too often except for requests from the same user, as there’s no preference for users to be routed to machines already running your worker script. Workers run on any one of thousands of machines, at any one of the hundreds of Cloudflare locations, chance of users landing on the same machines/using the same script is pretty low. For a single session from a single user, you’ll keep hitting the same machine until your connection dies though.

Also worth noting workers running on workers.dev have no cache ability, any cache operations will just do nothing. You need to use a Worker Custom Domain / Worker Routes in order to have a functional cache api.

1 Like

This topic was automatically closed after 15 days. New replies are no longer allowed.