演示

缓存

在根模块上用 @Cache 声明一个或多个缓存。用 @CacheClient 按所有者插件(及可选名称)注入——包括其他插件拥有的缓存。路由级与方法级辅助指向同一命名客户端。

技术栈

  • @Cache — 根 @Module;同一插件可声明多个命名缓存
  • @CacheClient(plugin, name?) — 注入本插件或其他插件的 ICache
  • @CacheRoute / @DeleteCacheRoute — 按 plugin + name
  • @CacheFn / @DeleteCacheFn — 按 plugin + name
  • 跨插件复用 — 消费方注入所有者的缓存,不要为同一客户端再声明 @Cache

根模块上的 @Cache

@Cache 必须加在 @Module 类上——不能加在 service 或 controller。打开多个缓存时传入唯一 name。同一模块类上允许多个 @Cache。

  • type — "in-memory" 或 Redis
  • name — 同一插件有多个 @Cache 时需要
  • 所有者是加载中的插件 — 消费方用 metadata.name(或 CacheManager.DEFAULT_PLUGIN)寻址
TSXmultiple caches in one plugin
1import { Cache, Module } from "@quan-erp/shared-backend-core"; 2import metadata from "../../module.metadata.json" with { type: "json" }; 3 4@Cache({ 5 name: "publisher", 6 type: "in-memory", 7 checkperiod: 1000, 8}) 9@Cache({ 10 name: "session", 11 type: "redis", 12 host: process.env.REDIS_HOST, 13 port: Number(process.env.REDIS_PORT ?? 6379), 14 password: process.env.REDIS_PASSWORD, 15}) 16@Module({ 17 name: metadata.name, 18 providers: [...], 19 controllers: [...], 20}) 21export class MyPluginModule {}

@CacheClient

在服务属性上注入 ICache。第一个参数是拥有该缓存的插件;第二个参数是可选连接名(该插件声明了多个 @Cache 时使用)。

  • CacheManager.DEFAULT_PLUGIN — 核心 / 共享默认所有者
  • metadata.name — 本插件自己的缓存
  • "other-plugin" — 其他插件创建的缓存
  • 第二个参数 name — 命名客户端(如 "publisher")
TSXinject
1import { 2 CacheClient, 3 CacheManager, 4 Service, 5} from "@quan-erp/shared-backend-core"; 6import type { ICache } from "@quan-erp/shared-backend-core"; 7import metadata from "../../module.metadata.json" with { type: "json" }; 8 9@Service() 10export class PublisherService { 11 // Core / default owner 12 @CacheClient(CacheManager.DEFAULT_PLUGIN, "publisher") 13 private defaultPublisher: ICache; 14 15 // This plugin’s named cache 16 @CacheClient(metadata.name, "session") 17 private session: ICache; 18 19 // Cache owned by another plugin 20 @CacheClient("warehouse", "replica") 21 private warehouseReplica: ICache; 22}

使用其他插件的缓存

缓存按所有者插件(+ 可选 name)登记在进程级注册表中。消费方不要为同一客户端再声明 @Cache,而是注入所有者的缓存,并让路由/方法辅助指向相同的 plugin + name。

  • 所有者 — 声明 @Cache,并先启动(写入 pluginDependencies)
  • 消费方 — @CacheClient("owner-plugin", "cache-name")
  • 路由 / 方法 — plugin + name 与所有者一致
  • 不要在每个消费方重复声明相同的 @Cache
TSXconsumer service
1import { CacheClient, Service } from "@quan-erp/shared-backend-core"; 2import type { ICache } from "@quan-erp/shared-backend-core"; 3 4@Service() 5export class ReportService { 6 // "warehouse" plugin declared @Cache({ name: "replica", ... }) 7 @CacheClient("warehouse", "replica") 8 private warehouseReplica: ICache; 9}

路由级

  • @CacheRoute({ key, plugin, name }) — key 可为字符串或 (req) => string
  • @DeleteCacheRoute({ key, plugin, name }) — 回调 key 必须返回 string[]
  • plugin + name 须匹配拥有该客户端的 @Cache(包括其他插件)
TSXroute cache
1import { 2 CacheRoute, 3 Controller, 4 DeleteCacheRoute, 5 Get, 6 Post, 7} from "@quan-erp/shared-backend-core"; 8 9@Controller("/branch") 10export class BranchController { 11 @Get("/") 12 @CacheRoute({ 13 key: (req) => `branch-${req.query.skip}-${req.query.limit}`, 14 plugin: "warehouse", 15 name: "replica", 16 }) 17 async list() { /* … */ } 18 19 @Post("/") 20 @DeleteCacheRoute({ 21 key: (req) => [`branch-${(req as any).user.payload.id}`], 22 plugin: "warehouse", 23 name: "replica", 24 }) 25 async create() { /* … */ } 26}

方法级

  • @CacheFn({ key, plugin, name }) — key 为 (...args) => string
  • @DeleteCacheFn({ key, plugin, name }) — key 返回 string[](允许通配符)
  • 与 @CacheClient / 路由辅助相同的 plugin + name 规则
TSXmethod cache
1import { 2 CacheFn, 3 CacheManager, 4 DeleteCacheFn, 5 Service, 6} from "@quan-erp/shared-backend-core"; 7import type { CreateJobDTO } from "./create-job.dto.js"; 8 9@Service() 10export class JobService { 11 @CacheFn({ 12 plugin: CacheManager.DEFAULT_PLUGIN, 13 name: "publisher", 14 key: (skip: number, limit: number) => `active-jobs-${skip}-${limit}`, 15 }) 16 async getActiveJobs(skip: number, limit: number) { /* … */ } 17 18 @DeleteCacheFn({ 19 plugin: CacheManager.DEFAULT_PLUGIN, 20 name: "publisher", 21 key: () => [`active-jobs-*`], 22 }) 23 async register(dto: CreateJobDTO) { /* … */ } 24}