jperasmus / stale-while-revalidate-cache

Storage-agnostic and configurable stale-while-revalidate cache helper for any function, for any JavaScript environment.
MIT License
62 stars 5 forks source link

Variable maxTimeToLive #15

Closed iplanwebsites closed 1 year ago

iplanwebsites commented 1 year ago

Great project! I need variable maxTimeToLive depending on some variable (API routes to be specefic). It sounds counter-productive to create a collection of SWR object for all these different cases. Is there any way to pass options to the swr() function that would override the initial settings?

For example:

import { createStaleWhileRevalidateCache, EmitterEvents } from 'stale-while-revalidate-cache'
import { metrics } from './utils/some-metrics-util.ts'

const swr = createStaleWhileRevalidateCache({
  storage: window.localStorage,  
  minTimeToStale: 5000, // 5 seconds default
  maxTimeToLive: 600000, // 10 minutes  global default
})

const productId = 'product-123456'
const functionSpeceficOptions = {
  minTimeToStale: 5, // 5 ms  it's already stale 
  maxTimeToLive: 600000000000000, // 20 years
  }
const product = await swr<Product>(productId, functionSpeceficOptions, async () => fetchProductDetails(productId))
jperasmus commented 1 year ago

Hi! This is not currently supported, but it sounds like a very useful feature. I'll take a look at it.

The API will likely look like this though, to avoid any unnecessary breaking changes:

// Support any of the main configs, essentially Partial<Config>
const optionalOverrides = {
  minTimeToStale: 5, // 5 ms  it's already stale 
  maxTimeToLive: 600000000000000, // 20 years
}

const product = await swr<Product>(productId, sync () => fetchProductDetails(productId), optionalOverrides)
jperasmus commented 1 year ago

You can try installing v2.1.0 and test if that works for you. The API is as I explained in my previous comment with the partial config object as 3rd argument.

iplanwebsites commented 1 year ago

Wow that was fast! Thanks! Just ran into another limitation, I'll open another issue just to keep things tidy.

enzolupia commented 3 months ago

Hi @jperasmus quick question here, I'll open a different thread if you want. How can I make configs override be applied also when I define a "custom" storage configuration?

For example, assume the swr configuration is the following

 const swr = createStaleWhileRevalidateCache({
    maxTimeToLive:  2000,
    minTimeToStale: 2000,
    storage: {
      async getItem(cacheKey: string) {
        return redis.get(cacheKey);
      },
      async setItem(cacheKey: string, cacheValue: string | number | Buffer) {
        if (cacheValue) {
          await redis.set(cacheKey, cacheValue, 'PX', 2000);
        }
      },
      async removeItem(cacheKey: string) {
        await redis.del(cacheKey);
      },
    },
  });

If I access SWR like this

const value = await swr(key, () => getValue(key), { maxTimeToLive:  600000000000000 })

I would expect the item to be cached for 600000000000000, instead it is always cached with a 2000 TTL (as per default configuration).

Am I doing something wrong?

jperasmus commented 3 months ago

Hi @enzolupia

In your case, it is not the library that is expiring your cached value but Redis. When SWR tries to read from your storage/redis, the value is no longer there.

The easiest way to fix it is to set a cache expiration on your redis config that is more than any max time to live config you want to use by default or via an override. That way the SWR library can handle all the expiration logic and your redis store will eventually clear in the background when the expiration time elapses.

enzolupia commented 3 months ago

Ok I see, thanks!