Worker cache is shorter than specified

I run imgproxy on my server and am using a worker to detect if the browser supports webp format and serve the correct image format for the browser requesting the image.
The image is supposed to be cached on Cloudflare forever (cacheTtl 1 year) if the image was fetched successfully. From the second fetch, cf-cache-status shows HIT as expected. However, the cache seems to expire after a few hours (cf-cache-status: MISS) instead of the 365 days specified.

The worker runs on a subdomain that I configured with the DNS entry:
CNAME img @ proxied:true

This is my worker:

addEventListener("fetch", event => {

 * Fetch and log a request
 * @param {Request} request
async function handleRequest(request) {
  // Parse request URL to get access to query string
  let url = new URL(request.url)

  const imageSrc = url.searchParams.get("src")
  if (!imageSrc) return new Response('Missing "src" value', { status: 400 })

  let imageWidth = url.searchParams.get("width");
  let imageHeight = url.searchParams.get("height");
  // Round up height/width to steps of 100 if no exact dimensions provided
  if (imageWidth && !imageHeight) imageWidth = Math.ceil(imageWidth / 100)*100;
  else if (imageHeight && !imageWidth) imageHeight = Math.ceil(imageHeight / 100)*100;

  // Your Worker is responsible for automatic format negotiation. Check the Accept header.
  const accept = request.headers.get("Accept");
  let supportsWebp = false
  if (/image\/webp/.test(accept)) {
    supportsWebp = true

  const imageURL = 'https://myimgproxyinstance.tld/preset:default/gravity:sm/resize:fill' 
  + (imageWidth ? ':'+imageWidth : '')
  + (imageHeight ? ':'+imageHeight : '')
  + (supportsWebp ? '/f:webp' : '')
  + '/' + imageSrc

  const response = await fetch(imageURL, {
    cf: {
      cacheTtlByStatus: { "200-299": 31536000, 404: 1, "500-599": 0 },
      cacheEverything: true,
  return new Response(response.body, { headers: response.headers });

The cache TTL is a maximum time not a minimum time. It can and will be evicted from cache at any time for a number of reasons (not enough hits, limited space, etc).

You should not rely on this to be exactly what you set but instead be up to what you set.


This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.

This is a follow-up to my last post that was auto-closed before I could reply, but the reply I received did not answer my question. When the edge cache is set to 1 year, it should not show cf-cache-status “MISS” in all cases after just one day. I am now also getting “cf-cache-status:EXPIRED” on some images that are supposed to be cached for one year and the “expires” header is always set to one hour.

Here is my last post: Worker cache is shorter than specified

Does anyone have an idea what I am doing wrong?

Let me expand what @WalshyMVP said.

Multiple things, actually, other than what he already said.

  1. The cf.cacheTtlByStatus key is available only to Enterprise customers, which make me think you are not able to use it.
    Cache using fetch · Cloudflare Workers docs
  2. I’d recommend using Workers’ Cache API, it’s easier to handle and you can deal with it.
    Cache · Cloudflare Workers docs
  3. About the expires header I am not sure, I don’t think Cloudflare sets it (unless you manually specify end user device caching rules), so it might come from the origin directly. Do check that.
  4. Workers run with each request, regardless, you can’t cache their response (you can cache the origin’s response, with the Cache API and the normal caching from Cloudflare (albeit less controllable).
1 Like

I modified the headers to remove expires:

  const headers = new Response(response.body, response).headers;
  return new Response(response.body, { headers });

I will see if that works, otherwise I will look into the Cache API. Thank you!

1 Like

Note that this is always still valid. Even with the Cache API.

The lower the plan level, in some locations more than others, it will be evicted fast if not requested often.