typescript 在tRPC 10中实现服务器端缓存中间件

8hhllhi2  于 12个月前  发布在  TypeScript
关注(0)|答案(1)|浏览(179)

我正在做一个Next.js项目,希望为tRPC结果实现内存缓存,每个tRPC过程都可以选择加入自定义TTL。我认为tRPC的中间件适合这个目的。不幸的是,current tRPC middleware documentation似乎没有涵盖这个特定的场景。
如何在tRPC 10中实现服务器端缓存中间件?

ulydmbyx

ulydmbyx1#

这里有一个关于Github issue的相关讨论,可以很容易地实现这一点。同时,仍然可以通过实现自定义逻辑来实现这一点。
下面的示例使用node-cache作为内存缓存方法。它已经在tRPC 10.43.3中测试过。cachedProcedures中列出的过程被配置为选择进入该高速缓存。

// 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 any & {
  __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;

个字符
几点意见:

  • 该示例假设Next.js应用路由器,但也应该与页面路由器或任何其他框架一起使用
  • 该高速缓存仅对query类型启用,而不是mutationsubscription
  • 它根据提供给过程的输入使用不同的缓存键
  • middlewareMarker是一个有点笨拙的修复,因为任何中间件返回都必须包含marker
  • structuredClone仅在Node 17+中可用,如果这不是一个选项,则需要其他深度克隆方法
  • 添加日志记录是明智的

相关问题