Backend - Any guidelines for Cache-Aside solution? #16033
Replies: 1 comment
-
|
Payload's built-in hooks can't short-circuit reads — Option 1: Wrap the Payload local API (DIY) Create helpers that check Redis before calling Payload: // lib/cache.ts
import { getPayload } from 'payload'
import config from '@payload-config'
import { redis } from './redis' // your ioredis/upstash client
const TTL = 60 * 60 // 1 hour
export async function findByIDCached<T>(collection: string, id: string): Promise<T> {
const key = `payload:${collection}:${id}`
const cached = await redis.get(key)
if (cached) return JSON.parse(cached) as T
const payload = await getPayload({ config })
const doc = await payload.findByID({ collection, id })
await redis.set(key, JSON.stringify(doc), 'EX', TTL)
return doc as T
}
export async function findCached<T>(collection: string, query: Record<string, unknown>): Promise<T> {
const key = `payload:${collection}:find:${JSON.stringify(query)}`
const cached = await redis.get(key)
if (cached) return JSON.parse(cached) as T
const payload = await getPayload({ config })
const result = await payload.find({ collection, ...query })
await redis.set(key, JSON.stringify(result), 'EX', TTL)
return result as T
}Then use // collections/MyCollection.ts
import type { CollectionConfig } from 'payload'
import { redis } from '../lib/redis'
export const MyCollection: CollectionConfig = {
slug: 'my-collection',
hooks: {
afterChange: [
async ({ doc, collection }) => {
// Invalidate the specific document
await redis.del(`payload:${collection.config.slug}:${doc.id}`)
// Invalidate list queries for this collection (simplest strategy)
const keys = await redis.keys(`payload:${collection.config.slug}:find:*`)
if (keys.length) await redis.del(keys)
},
],
afterDelete: [
async ({ doc, collection }) => {
await redis.del(`payload:${collection.config.slug}:${doc.id}`)
const keys = await redis.keys(`payload:${collection.config.slug}:find:*`)
if (keys.length) await redis.del(keys)
},
],
},
fields: [
// ...
],
}A note on list cache invalidation: Option 2: Use a community plugin If you'd rather not write the plumbing yourself, payloadcms-redis-plugin adds transparent caching at the database adapter level with automatic invalidation on write operations. It covers the same use case with less custom code. Which to pick? If you need fine-grained control over TTLs, cache keys, or invalidation logic per collection, the DIY wrapper is cleaner. If you just want "don't hit Postgres every time" with minimal code, the plugin is faster to ship. Either way, the |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I have not found a documented way for doing cache-aside.
Instead of hitting Postgres every time, I want to hit Redis first, verify if the value is already there, if that is the case, I want to return the cached value.
I also want to be able to update the value, after the value is updated on the database.
I believe this is a very standard technique and payload should support it. If there is anything I can help with, let me know.
Beta Was this translation helpful? Give feedback.
All reactions