next-shared-cache
next-shared-cache copied to clipboard
Time based revalidation does not work as expected
This effects both Next.js 14 and 15.
When setting { next: { revalidate: 1 } }, currently the default behaviour of the redis-strings and redis-stack handlers is to set an expiry on the entry set in Redis.
However, the expected behaviour of Time-based Revalidation is that if you set the revalidate option like so on a fetch request.
// Revalidate at most every hour
fetch('https://...', { next: { revalidate: 1 } })
After the initial request has fetched the data from the external data source and stored it in the Data Cache, it will continue you return this cached data until it expires.
Even when it expires, it should return stale data, while fetching updated data in the background and updating the Data Cache (so the subsequent request will be up to date).
If the expiry is set on the entry in Redis when it is created, then it will not be able to return stale data and will instead always be fetching from the external data source and no data will ever be in the cache.
@jshbrntt Hey there!
@neshca/cache-handler supports time-based revalidation and lets you adjust the cache expiration time. By default, the stale time of the cache matches the expiration time to conserve space in the cache storage. You can customize the stale time by setting the estimateExpireAge callback in the options. For further details, check out the documentation.
Setting the expiration age to be the same as the stale age is quite stringent. I plan to update the default estimateExpireAge in the upcoming major release, including Next.js 15 and node-redis 5 support. Keep an eye out for it!
@better-salmon how do I get this exact behaviour in the diagram?
https://nextjs.org/docs/app/building-your-application/caching#time-based-revalidation
It should always serve from cache even if it's stale, revalidate and update the cache with fresh data in the background.
Therefore not blocking the page load and not making it wait for a delete or set call on the cache.
I tried setting the options you linked to in the docs. https://caching-tools.github.io/next-shared-cache/api-reference/ttl-parameters#estimateexpireage
Although they fix the issue of setting the TTLs of the Redis cache entries to be longer than that of the revalidate value so they're still retrievable to be served as stale cache values.
When the revalidation/refresh of the stale cache is triggered the page response is delayed as if it was fetching directly from the external data source. I think this is because it is awaiting a get (stale data), delete (stale data), fetch (fresh data) and a set (fresh data) before returning the page response.
When it should be doing the last 3 parts in the background outside of the page response flow.
@better-salmon I'm still getting slow page responses from Next.js due to the cache handler waiting for...
get (stale data)- Next.js has all the data it needs at this point so it should be rendering the page and responding...
delete (stale data)fetch (fresh data)set (fresh data)- Next.js only starts rendering the page and responding at this point.
This appears to be the case looking at the OpenTelemetry traces, you can see the initial waterfall of GET requests from Redis that resolve quickly, but the page response span finishes only when some later SET calls have finished.