nitro icon indicating copy to clipboard operation
nitro copied to clipboard

Expired cache entries do not get flushed

Open tdekoning opened this issue 2 years ago • 2 comments

Environment

Nitropack 2.8.1 Nuxt 3.10.1

Reproduction

Reproduction repo: https://stackblitz.com/edit/github-g1zu3w

  1. Start the app
  2. Click on "Go to A"
  3. See that "A" renders
  4. go back to the index route
  5. Click "Go to B"
  6. See that "B" renders
  7. Go in the file explorer to "/.nuxt/cache/nitro/routes/_" and see there are 3 records (index, A and B)
  8. Refresh "B" after more than 5 seconds
  9. See that the cache-record of "B" is updated, but the cache-record of "A" is still present (the fact that it stays present is the problem)

Describe the bug

When using SSR with cache old expired records never get flushed. This results in the filesystem or memory (depending on what cache-storage is used) to fill up over time.

Note that every unique URL is a cache-record, this includes query-parameters. So users can potentially fill up the cache of any Nuxt/Nitro server with ease, resulting in down time.

Additional context

No response

Logs

No response

tdekoning avatar Feb 06 '24 08:02 tdekoning

Small addition as I've been working on this to solve the out of memory issue. The default storage driver configured for cache storage at build time is a memory driver. So each time a page is cached an item is pushed to the memory cache. This item will exist forever, because the driver has no TTL option.

See: https://github.com/unjs/nitro/blob/5b0e150e1fcdaba8ac6f75dfe40c28b42b5a188c/src/runtime/cache.ts#L121

As temporary solution we configured the storage driver with redis at runtime using a plugin.

rhelling avatar Feb 27 '24 13:02 rhelling

I think this is partially fixed in current v2 branch also in v3, but that would only work for drivers that do support TTL like redis and not for a filesystem or memory drivers.

I want to raise another thing here as well, for use-cases like tracing, it means cache hits would be incorrectly reported for such drivers.

I'm thinking a good compromise here is to require the storage API connectors/drivers to always support TTL, and move the TTL validation logic to the driver/connector implementation to be decided there rather than the framework.

For example:

  • For storage that supports TTL (e.g: redis): Already passing TTL to the underlying connector, no issue.
  • For storage that doesn't support TTL (e.g: filesystem): Make it so that get operations perform the same TTL check that Nitro uses, so if an item expires, flush it and return null.

This would make all get operations consistent across all drivers when it comes to TTL and expiry. It doesn't solve flushing for the original issue here.

logaretm avatar Oct 11 '25 11:10 logaretm