GraphQL SWR 快取(NestJS,code-first)
概述
依意圖而非機制進行快取。一個策略形狀、一個可觀察的事件流、一個每請求的追蹤。預設掛載於服務層級;僅在經過衡量後才升級到欄位/操作/傳輸層。
三個塑造每個決策的殘酷事實:
- Apollo Server 沒有內建的 stale-while-revalidate。 它的
responseCachePlugin僅是 TTL 且是操作層級的。真正的 SWR 來自你自己的層(async-cache-dedupe,或基於 Mercurius 驅動程式的mercurius-cache)或來自 CDN。 - 範圍預設為
public。 一個公開的條目會被每個呼叫者逐字共享,所以它只有在結果對於所有呼叫者都是位元組完全相同時才是正確的。當一個值因呼叫者而異時,它必須被標記為perUser—否則就會發生資料洩漏。 - Nest 攔截器不會包裹服務方法,而且
@nestjs/cache-manager的CacheInterceptor在 GraphQL 中無法運作。 因此,你想要的服務層級裝飾器是一個包裝在去重引擎之上的方法包裝器,而不是一個框架攔截器。
何時使用
- 解析器/服務反覆存取資料庫或上游 API 的 NestJS GraphQL(code-first)應用程式。
- 你需要消除 TTL 到期時的延遲峰值和 stampede 效應(真正的 SWR)。
- 你需要推理多用戶快取的安全性/資料洩漏問題。
- 你需要檢視 hit / stale / miss 的決策。
- 你需要用一個標誌完全關閉快取—開發環境、CI 或事故處理時(參見第 1 節,
setup-disable-switch)。 - 你正在為一個應用程式首次配置快取功能(參見第 1 節)。
何時不使用:
- 你已經在 CDN 之後對公開的 GET/APQ 流量進行回應快取—從那裡開始。
- 寫入/突變路徑,或沒有重複使用且讀取放大率低的每個用戶資料(快取帶來的風險大於收益)。
回呼合約
key、@CacheTag 和 @InvalidateTags 接受函式。搞錯它們的引數會導致快取靜默地錯失命中,而且標籤靜默地無法清除。
| 回呼 | 簽名 | args 是什麼 |
|---|---|---|
key | (args, ctx) => unknown[] | Promise<unknown[]> | 方法的引數列表,按呼叫順序— args[0],絕非 args.id |
@CacheTag | (result, args) => string[] | null | 相同的列表;result 是方法的回傳值 |
@InvalidateTags | (result, args) => string[] | 相同的列表;result 是寫入操作的回傳值 |
- 按位置,而非名稱。 對
getTitle(id: string)來說,id 是args[0]。 - 在兩個標籤回呼中,
result都是第一個參數。 原始引擎自己的references是(args, key, result)—順序不同,第一個參數也不同(請參閱driver-async-cache-dedupe)。 ctx(userId、tenantId、locale,加上gen)衍生自請求,並由buildCacheContext組裝;它在請求外部是空的,因此一個批次作業會將其需要的內容作為引數傳入。- 型別化:預設值是
unknown[]/unknown—請註解 tuple(@Cacheable<[string]>、@CacheTag<[string]>),否則回呼主體將無法編譯。 - 欄位層級不同:在那裡,
args是解析器的具名引數物件,而ctx是 GraphQL 上下文(driver-mercurius-cache)。
完整合約、金鑰組合 { a, k, u } 以及序列化的邊界案例:policy-key-derivation。執行時期實作:setup-decorator-runtime。
按優先級分類的規則
| 優先級 | 類別 | 影響 | 前綴 |
|---|---|---|---|
| 1 | 一次性設定 | 關鍵 | setup- |
| 2 | 快取策略 | 關鍵 | policy- |
| 3 | 資料洩漏安全 | 關鍵 | safety- |
| 4 | 失效 | 高 | invalidation- |
| 5 | 可觀察性 | 中 | observability- |
| 6 | 驅動程式 | 中 | driver- |
快速參考
1. 一次性設定(關鍵)
setup-decorator-runtime- 將裝飾器實作為具有穩定名稱的方法包裝器setup-disable-switch- 提供一個可繞過服務層級快取的配置開關setup-engine-choice- 使用去重引擎,並以秒為單位計算 TTLsetup-fail-open- 故障時開放,且絕不快取錯誤setup-file-placement- 根據誰匯入它來放置該能力setup-identity-context- 從 AsyncLocalStorage 而非 Scope.REQUEST 讀取呼叫者setup-module-wiring- 使用 forRootAsync 一次性配置快取模組setup-storage-and-invalidation- 啟用失效並設定 referencesTTL 和 GC
2. 快取策略(關鍵)
policy-five-knobs- 了解五個調節鈕policy-key-derivation- 自動推導金鑰,絕不使用 JSON.stringifypolicy-mount-at-service- 預設掛載於服務層級policy-one-writing-pattern- 裝飾器是唯一的寫入模式policy-service-escape-hatch- 服務 API 是一個逃生艙口,而非第二種模式
3. 資料洩漏安全(關鍵)
safety-default-public- 範圍預設為公開—將因呼叫者而異的讀取標記為 perUsersafety-key-dimensions- 範圍僅涵蓋用戶—所有其他維度都放入金鑰中safety-no-leak-checklist- 對每個快取讀取執行無資料洩漏檢查清單
4. 失效(高)
invalidation-after-success- 僅在成功寫入後才失效invalidation-atomic-purge- 原子性清除並限制標籤基數invalidation-generation-prefix- 對巨大或粗略的領域使用世代前綴invalidation-tags-purge-only- 標籤僅供清除使用,絕不用於查詢
5. 可觀察性(中)
observability-limits-of-events- 了解引擎無法報告的內容observability-metrics-and-tests- 追蹤能證明修復的指標,並根據結果進行測試observability-per-request-trace- 提供每請求追蹤,在 GraphQL 上僅供開發使用observability-structured-events- 發射結構化的快取事件,而非日誌字串
6. 驅動程式(中)
driver-apollo-response-cache- 選項 C — Apollo responseCachePlugin(操作層級,僅 TTL)driver-apollo-vs-mercurius- 從你的驅動程式中選擇欄位層級選項driver-async-cache-dedupe- 選項 A — async-cache-dedupe(服務層級,傳輸無關)driver-cdn-transport- 選項 E — 傳輸 / CDN SWR(僅限公開讀取)driver-envelop-response-cache- 選項 D — Envelop useResponseCache(非 NestJS 原生)driver-federation-router- 僅限 Federation — Apollo Router 回應快取driver-mercurius-cache- 選項 B — mercurius-cache(欄位層級,真正的 SWR)driver-version-pinning- 鎖定版本—此區域容易變動
如何使用
從一次性設定章節開始,然後閱讀策略、安全性和失效規則以解決你當前面臨的決策。規則檔案位於 rules/ 目錄下:
rules/setup-module-wiring.md
rules/_sections.md
每個規則檔案包含:
- 規則的內容以及它防止的失敗
- 一個帶有說明的錯誤範例
- 一個帶有說明的正確範例
- 參考資料
完整彙編文件
如需包含所有已展開規則的完整指南,請參閱 AGENTS.md。