core icon indicating copy to clipboard operation
core copied to clipboard

[question] Invalidating cache bases

Open remihuigen opened this issue 11 months ago • 4 comments

I was wondering what the most efficient way is to clear cache bases.

I was looking at this bit of code, where you're clearing a base 100 keys at a time

I've been trying to make unstorage's clear() method work , but with no luck (which is probably why nuxthub uses batches of 100 keys).

I have two questions related to this:

  • Why doesnt the clear method work?
  • What if a want to invalidate thousands of keys at a time? I would likely run into these limits: https://arc.net/l/quote/omawzasz

remihuigen avatar Mar 24 '25 13:03 remihuigen

Hi @remihuigen

The biggest issue is that they don't allow to bulk delete using the binding:

Image

Actually I should change the batch to 10,000 keys so it will avoid making many calls, it won't run into the limits at using the batch delete.

How did you try to use the clear() method from unstorage?

I could expose a hubCache().clear(base) to make it work both locally, remotely & in production, would that help?

atinux avatar Mar 28 '25 09:03 atinux

That would be great!

I think i tried both await useStorage('cache').clear(base) and await useStorage(`cache:${base}`).clear()

my current implementation is practically the same as yours

export default defineEventHandler(async (event) => {
  authenticateRequest(event)

  const { bases } = getQuery(event)

  let cacheBases: string[] = typeof bases === 'string' ? bases.split(',') : Array.isArray(bases) ? bases : []

  if (!cacheBases?.length) {
    cacheBases = [
      'nitro:routes',
      'pages',
      'kennisbank',
      'media',
      'navigator',
      'routes'
    ]
  }

  const baseKeys = cacheBases.map(base => !base.startsWith('cache:') ? `cache:${base}` : base)

  // Code is similar to https://github.com/nuxt-hub/core/blob/main/src/runtime/cache/server/api/_hub/cache/clear/%5B...base%5D.delete.ts
  // Except were clearing multiple bases at once
  await Promise.all(baseKeys.map(async (base) => {
    const storage = useStorage(base)
    const keys = await storage.getKeys()
    do {
      const keysToDelete = keys.splice(0, 100)
      await Promise.all(keysToDelete.map(async key => await storage.removeItem(key)))
    } while (keys.length)
  }))
  return {
    message: `Cache invalidated.`,
    bases: baseKeys
  }
})

remihuigen avatar Mar 28 '25 11:03 remihuigen

I also just now noted that await hubKV().clear(prefix) doesn't seem to work. Using await hubKV().clear() without a prefix clears all KV entries

I'm using it as documented here

remihuigen avatar Mar 29 '25 21:03 remihuigen