我正在开发一个Next.js项目,希望实现tRPC结果的内存缓存,每个tRPC过程都能够 Select 加入一个定制的TTL.我认为tRPC的中间件将适合于此目的.不幸的是,current tRPC middleware documentation似乎不包括这一特定场景.
如何在tRPC 10中实现服务器端缓存中间件?
我正在开发一个Next.js项目,希望实现tRPC结果的内存缓存,每个tRPC过程都能够 Select 加入一个定制的TTL.我认为tRPC的中间件将适合于此目的.不幸的是,current tRPC middleware documentation似乎不包括这一特定场景.
如何在tRPC 10中实现服务器端缓存中间件?
对于允许轻松实现这一点的功能请求,在Github issue上有一个相关的讨论.同时,仍然可以通过实现定制逻辑来实现这一点.
下面的示例使用node-cache
作为内存缓存方法.它已经在tRPC 10.43.3上进行了测试.cachedProcedures
中列出的过程被配置为 Select 进入高速缓存.
// src/app/api/middleware/cache.ts
import { initTRPC } from "@trpc/server";
import NodeCache from "node-cache";
const cacheSingleton = new NodeCache();
// A map of cached procedure names to a callable that gives a TTL in seconds
const cachedProcedures: Map<string, (() => number) | undefined> = new Map();
cachedProcedures.set("router0.procedure0", () => 2 * 3600); // 2 hours
cachedProcedures.set("router0.procedure1", () => 1800); // 30 minutes
cachedProcedures.set("router1.procedure0", secondsUntilMidnight); // dynamic TTL
cachedProcedures.set("router1.procedure1", () => undefined); // never expires
const t = initTRPC.create();
const middlewareMarker = "middlewareMarker" as "middlewareMarker" & {
__brand: "middlewareMarker";
};
const cacheMiddleware = t.middleware(
async ({ ctx, next, path, type, rawInput }) => {
if (type !== "query" || !cachedProcedures.has(path)) {
return next();
}
let key = path;
if (rawInput) {
key += JSON.stringify(rawInput).replace(/\"/g, "'");
}
const cachedData = cacheSingleton.get(key);
if (cachedData) {
return {
ok: true,
data: cachedData,
ctx,
marker: middlewareMarker,
};
}
const result = await next();
//@ts-ignore
// data is not defined in the type MiddlewareResult
const dataCopy = structuredClone(result.data);
const ttlSecondsCallable = cachedProcedures.get(path);
if (ttlSecondsCallable) {
cacheSingleton.set(key, dataCopy, ttlSecondsCallable());
} else {
cacheSingleton.set(key, dataCopy);
}
return result;
}
);
export default cacheMiddleware;
// src/server/api, or wherever you define tRPC procedures
import cacheMiddleware from "@/app/api/middleware/cache";
...
export const publicProcedure = t.procedure.use(cacheMiddleware);
以下是几点意见:
query
种类型启用,而不是mutation
或subscription
middlewareMarker
是一个有点老生常谈的修复,因为任何中间件返回必须包括marker
structuredClone
仅在 node 17+中可用,如果这不是一个选项,则需要不同的深度克隆方法