Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ while GitHub shows only its `--8<--` include line (the sentence before each
block links the example file).

- [Migrating to 0.4.0](https://fastapi-cachex.readthedocs.io/en/latest/MIGRATING_0_4/) — what 0.4.0 changes and how to upgrade from 0.3.x
- [When to use it](https://fastapi-cachex.readthedocs.io/en/latest/COMPARISON/) — how it compares with fastapi-cache2, cashews, aiocache and a CDN, and when another one fits better
- [HTTP caching](https://fastapi-cachex.readthedocs.io/en/latest/HTTP_CACHING/) — the `@cache` decorator, Cache-Control directives, cache keys, invalidation and monitoring routes
- [Application cache](https://fastapi-cachex.readthedocs.io/en/latest/APP_CACHE/) — `CacheManager`
- [Backends](https://fastapi-cachex.readthedocs.io/en/latest/BACKENDS/) — choosing and configuring a backend, atomic primitives
Expand Down
162 changes: 162 additions & 0 deletions docs/COMPARISON.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# When to use FastAPI-CacheX

FastAPI-CacheX caches HTTP responses inside a FastAPI app and gets the HTTP
semantics around them right: `Cache-Control`, `ETag` and `If-None-Match`,
`Vary`, and requests that carry credentials. It also has a small application
cache and a distributed lock on the same backends. It is not the right tool for
every caching job. This page says what it does well, what the other common
choices do well, and when one of them fits better.

The other libraries are described as of their latest release in October 2026.
If something here is out of date, please
[open an issue](https://github.com/allen0099/FastAPI-CacheX/issues).

## At a glance

Facts about the other libraries are from their source code at the release
named in the last row. A feature marked 0.4.2 is not in a FastAPI-CacheX
release yet.

| | FastAPI-CacheX | fastapi-cache2 | cashews | aiocache |
|---|---|---|---|---|
| What it caches | FastAPI GET responses; JSON values; function results (`@cached`, 0.4.2) | Return values of endpoints and plain functions | Return values of any async function | Return values of any async function; a key-value API |
| Key built from | Method, host, path and query of the request | Function module, name and arguments | Function name and arguments, or a template | Function name and arguments, or a key builder |
| `Cache-Control`, `ETag`, `304` | Written from the decorator's arguments; `304` on a matching `If-None-Match` | `max-age`, a weak `ETag` and `304` when the endpoint takes a `Response` | With its `CacheRequestControlMiddleware` and `CacheEtagMiddleware` | None |
| A client's `Cache-Control` request header | Ignored, so clients cannot skip the cache | `no-store` and `no-cache` are honoured | Honoured by the middleware (`no-cache`, `no-store`, `max-age`) | — |
| Requests with `Authorization` or a session | Bypass the shared cache unless you opt in | Cached like any other request | Your choice of key and middleware settings | — |
| Serialization | JSON, no pickle | JSON by default, pickle optional | Pickle by default, optionally HMAC-signed; JSON optional | Pickle, JSON, msgpack, string or none |
| Backends | Memory, Redis, Memcached | Memory, Redis, Memcached, DynamoDB | Memory, Redis (incl. cluster and client-side caching), diskcache | Memory, Redis, Memcached |
| Stampede protection | `get_or_set()` with a distributed lock; `coalesce=True` per process on `@cache` (0.4.2) | None | `locked`, `early`, `soft`, `thunder_protection` | `cached_stampede` (lock based) |
| Tags, early refresh, metrics | No | No | Tags, early and soft refresh, Prometheus middleware, callbacks | Hit/miss and timing plugins |
| Also included | `CacheLock`, atomic counters, monitoring routes | — | Rate limiting, circuit breaker, Bloom filters, locks | `RedLock`, `OptimisticLock`, `multi_cached` |
| Latest release | 0.4.1 (2026-10-03); Python 3.10+, FastAPI 0.133+, Starlette 1.0+ | 0.2.2 (2024-07-24); Python 3.8+ | 7.6.0 (2026-09-17); Python 3.10+ | 0.12.3 (2024-09-25) |

## FastAPI-CacheX

Choose it when the thing you cache is a **FastAPI response** and you want the
cache to behave like an HTTP cache:

- **HTTP semantics.** `@cache` writes `Cache-Control` from its arguments,
adds a weak `ETag` and answers a matching `If-None-Match` with `304`,
also on a miss and on `no_cache` routes. It sends `Age` on a hit, honours
`Vary` (`vary=` adds request headers to the key), and answers `HEAD` from
the cached `GET` (0.4.2). See [HTTP caching](HTTP_CACHING.md).
- **Safe by default with credentials.** The default key carries no user
identity, so a request with `Authorization` or a session bypasses the shared
cache and is answered with `Cache-Control: private`, and a response that sets
a cookie is never stored. You opt in to sharing with `public=True`, or to a
per-user entry with `cache_authorized=True` and a key builder that names
the user (see [Requests with credentials](HTTP_CACHING.md#requests-with-credentials)).
- **Keys from the request.** The key is the method, host, path and sorted
query string, so it matches what an HTTP cache downstream sees, and a route
can be dropped with `invalidate(request)` or `clear_path()`.
- **No pickle.** Responses and `CacheManager` values are stored as JSON, so
an entry read from a shared Redis cannot run code when it is decoded.
- **Fails open.** If the backend is down, `@cache` logs it and runs the
handler, so a cache outage does not become an API outage.
- **Small extras on the same backend.** `CacheManager` / `AppCache` with
`get_or_set()` behind a distributed lock, `@cached` for plain functions
(0.4.2), and `CacheLock` for one holder across workers.

What it does not do, or does only simply:

- Only `GET` (and `HEAD`) responses are cached; there is no caching of `POST`.
- Function caching is basic: no early or probabilistic refresh, no tags, no
serving of stale values while one caller refreshes, no metrics hooks.
- Three backends: memory, Redis and Memcached. Memcached cannot enumerate
keys, so pattern and path clearing do nothing there.
- The server-side cache never serves stale content; `stale-while-revalidate`
and `stale-if-error` are only written into the header for downstream caches.

## fastapi-cache2

[fastapi-cache2](https://github.com/long2ice/fastapi-cache) is the most
installed FastAPI cache. `@cache(expire=60)` caches the return value of an
endpoint or any other function, keyed on the function's module, name and
arguments.

Choose it when:

- You already use it and it works for you. Its API is small and well known.
- You want one decorator for endpoints and helper functions alike, keyed on
their arguments.
- You need DynamoDB, or Python 3.8 or 3.9.

Points to know when comparing:

- The key does not include the URL. Two requests that reach the same
arguments share an entry, and a response that depends on something outside
the arguments, such as a header the handler reads through `Request`, needs a
custom `key_builder`.
- Requests with `Authorization` or a cookie are cached like any other. A
per-user endpoint must put the user into the key itself.
- Its latest release is from July 2024.

## cashews

[cashews](https://github.com/Krukov/cashews) is a general caching toolkit for
async Python, with the widest feature set of the libraries here.

Choose it when you cache **function results** more than HTTP responses and
need more than a TTL:

- Early or soft refresh, so a hot key is recomputed before it expires instead
of every caller waiting on a miss.
- Tags, to drop every entry that depends on one record.
- Rate limiting, a circuit breaker, Bloom filters and locks from the same
setup.
- Prometheus metrics, Redis Cluster, Redis client-side caching or a disk
cache.

Its FastAPI middlewares add `Cache-Control`, `Age` and `ETag` handling. Unlike
`@cache` here, they let a client's `Cache-Control: no-cache` or `max-age=0`
skip the cache, which is useful for debugging and lets any client send
requests straight to the handler. Values are pickled by default; set a
`secret` so they are signed, or choose the JSON pickler, if anyone else can
write to your Redis.

## aiocache

[aiocache](https://github.com/aio-libs/aiocache) is a general async key-value
cache with decorators (`@cached`, `@cached_stampede`, `@multi_cached`),
pluggable serializers and plugins for hit/miss ratios and timing. It has no
HTTP or FastAPI features of its own.

Choose it when you want a plain async cache API, outside FastAPI or alongside
any web framework, and will handle HTTP headers yourself. Its latest release is
from September 2024.

## An HTTP cache or CDN in front of the app

A reverse proxy (nginx, Varnish) or a CDN (Cloudflare, Fastly, CloudFront)
caches responses before they reach Python at all. For **public responses that
are the same for every visitor**, such as a home page, an article or a public
product list, this is usually the better choice: a hit costs no worker time,
the cache sits close to the client, and it absorbs traffic spikes your app
servers would otherwise take.

It fits less well when:

- The response depends on who is asking. A shared cache keys on the URL (plus
the headers named in `Vary`), so keeping per-user responses apart there is
easy to get wrong, and a shared cache does not store a response to a request
with `Authorization` unless the response explicitly allows it.
- You need to drop an entry from application code the moment the data
changes, without a call to the CDN's purge API.
- You do not run a proxy or CDN, for example for an internal API.

The two combine. `@cache` writes the `Cache-Control` and `ETag` headers a CDN
reads, so the CDN can serve public routes while `@cache` keeps a server-side
copy for the requests that still reach the app (a cold edge, or a
`no-cache` revalidation). Be careful with `public=True`: it tells every cache downstream that it may
store the response even though the request carried credentials.

## Which one to choose

| You want to… | A good fit |
|--------------|------------|
| Cache FastAPI GET responses with correct `Cache-Control`, `ETag` and `304`s, and keep per-user responses out of the shared cache | FastAPI-CacheX |
| Serve public pages to many visitors at the lowest cost | A CDN or reverse proxy, with `@cache` writing its headers |
| Cache function results with early refresh, tags, rate limiting or metrics | cashews |
| A framework-independent async key-value cache | aiocache, or cashews |
| Keep an existing fastapi-cache2 setup that works for you | fastapi-cache2 |
98 changes: 98 additions & 0 deletions i18n/zh-TW/docs/COMPARISON.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# 何時使用 FastAPI-CacheX {#when-to-use-fastapi-cachex}

FastAPI-CacheX 在 FastAPI 應用程式內快取 HTTP 回應,並正確處理相關的 HTTP 語意:`Cache-Control`、`ETag` 與 `If-None-Match`、`Vary`,以及帶有憑證的請求。它也在同樣的後端上提供一個小型的應用層快取和分散式鎖。它不是每一種快取需求的最佳工具。本頁說明它擅長什麼、其他常見選擇擅長什麼,以及什麼時候其他選擇更合適。

其他函式庫的說明以它們在 2026 年 10 月的最新版本為準。如果內容已經過時,歡迎[開 issue](https://github.com/allen0099/FastAPI-CacheX/issues)。

## 一覽 {#at-a-glance}

其他函式庫的資訊取自最後一列所列版本的原始碼。標示 0.4.2 的功能尚未包含在 FastAPI-CacheX 的任何發行版中。

| | FastAPI-CacheX | fastapi-cache2 | cashews | aiocache |
|---|---|---|---|---|
| 快取的對象 | FastAPI 的 GET 回應;JSON 值;函式結果(`@cached`,0.4.2) | 端點與一般函式的回傳值 | 任何非同步函式的回傳值 | 任何非同步函式的回傳值;鍵值 API |
| 快取鍵的來源 | 請求的方法、主機、路徑與查詢字串 | 函式的模組、名稱與引數 | 函式名稱與引數,或樣板 | 函式名稱與引數,或 key builder |
| `Cache-Control`、`ETag`、`304` | 依裝飾器的參數產生;`If-None-Match` 相符時回 `304` | 端點接收 `Response` 時,送出 `max-age`、弱 `ETag` 並回 `304` | 透過它的 `CacheRequestControlMiddleware` 與 `CacheEtagMiddleware` | 無 |
| 用戶端請求的 `Cache-Control` 標頭 | 忽略,用戶端無法略過快取 | 遵循 `no-store` 與 `no-cache` | 由中介軟體遵循(`no-cache`、`no-store`、`max-age`) | — |
| 帶 `Authorization` 或 Session 的請求 | 略過共用快取,除非明確選擇共用 | 和其他請求一樣被快取 | 取決於你的快取鍵和中介軟體設定 | — |
| 序列化 | JSON,不用 pickle | 預設 JSON,可選 pickle | 預設 pickle,可選 HMAC 簽章;可選 JSON | pickle、JSON、msgpack、字串或不序列化 |
| 後端 | 記憶體、Redis、Memcached | 記憶體、Redis、Memcached、DynamoDB | 記憶體、Redis(含 cluster 與 client-side caching)、diskcache | 記憶體、Redis、Memcached |
| Stampede 防護 | `get_or_set()` 搭配分散式鎖;`@cache` 的 `coalesce=True` 在單一行程內合併(0.4.2) | 無 | `locked`、`early`、`soft`、`thunder_protection` | `cached_stampede`(以鎖實作) |
| 標籤、提前更新、指標 | 無 | 無 | 標籤、early 與 soft 提前更新、Prometheus 中介軟體、回呼 | 命中率與計時外掛 |
| 其他功能 | `CacheLock`、原子計數器、監控路由 | — | 速率限制、斷路器、Bloom filter、鎖 | `RedLock`、`OptimisticLock`、`multi_cached` |
| 最新版本 | 0.4.1(2026-10-03);Python 3.10+、FastAPI 0.133+、Starlette 1.0+ | 0.2.2(2024-07-24);Python 3.8+ | 7.6.0(2026-09-17);Python 3.10+ | 0.12.3(2024-09-25) |

## FastAPI-CacheX {#fastapi-cachex}

當你要快取的是 **FastAPI 回應**,而且希望快取的行為和 HTTP 快取一致時,選擇它:

- **HTTP 語意。** `@cache` 依參數產生 `Cache-Control`,加上弱 `ETag`,並在 `If-None-Match` 相符時回 `304`,快取未命中和 `no_cache` 路由也一樣。命中時送出 `Age`,遵循 `Vary`(`vary=` 把請求標頭加進快取鍵),並以快取的 `GET` 回應 `HEAD`(0.4.2)。見 [HTTP 快取](HTTP_CACHING.md)。
- **預設對帶憑證的請求安全。** 預設的快取鍵不含使用者身分,所以帶 `Authorization` 或 Session 的請求會略過共用快取,並以 `Cache-Control: private` 回應;設定 cookie 的回應永遠不會存入快取。要共用時設定 `public=True`;要每個使用者各自一筆項目時,設定 `cache_authorized=True` 並搭配把使用者放進快取鍵的 key builder(見[帶有憑證的請求](HTTP_CACHING.md#requests-with-credentials))。
- **快取鍵來自請求。** 快取鍵是方法、主機、路徑與排序後的查詢字串,和下游 HTTP 快取看到的一致,也可以用 `invalidate(request)` 或 `clear_path()` 讓路由的快取失效。
- **不用 pickle。** 回應與 `CacheManager` 的值都以 JSON 儲存,從共用的 Redis 讀出的項目在反序列化時不會執行程式碼。
- **失敗時放行(fail open)。** 後端無法使用時,`@cache` 記錄日誌並執行 handler,快取故障不會變成 API 故障。
- **同一個後端上的小工具。** `CacheManager`/`AppCache` 的 `get_or_set()` 以分散式鎖保護,`@cached` 快取一般函式(0.4.2),`CacheLock` 讓多個 worker 之間同時只有一個持有者。

它不做、或只簡單做到的事:

- 只快取 `GET`(以及 `HEAD`)回應,不快取 `POST`。
- 函式快取很基本:沒有提前或機率式更新、沒有標籤、不會在一個呼叫者更新時提供過期值、沒有指標掛鉤。
- 三種後端:記憶體、Redis 與 Memcached。Memcached 無法列舉鍵,所以依模式或路徑清除在它上面不會有任何作用。
- 伺服器端快取永遠不提供過期內容;`stale-while-revalidate` 和 `stale-if-error` 只寫進標頭給下游快取使用。

## fastapi-cache2 {#fastapi-cache2}

[fastapi-cache2](https://github.com/long2ice/fastapi-cache) 是安裝數最多的 FastAPI 快取。`@cache(expire=60)` 快取端點或任何函式的回傳值,快取鍵取自函式的模組、名稱與引數。

以下情況選擇它:

- 你已經在用,而且運作良好。它的 API 小且廣為人知。
- 你想用同一個裝飾器處理端點和輔助函式,並以引數作為快取鍵。
- 你需要 DynamoDB,或需要支援 Python 3.8 或 3.9。

比較時要注意:

- 快取鍵不包含 URL。兩個得到相同引數的請求共用同一筆項目;如果回應取決於引數以外的東西,例如 handler 透過 `Request` 讀取的標頭,就需要自訂 `key_builder`。
- 帶 `Authorization` 或 cookie 的請求和其他請求一樣被快取。每個使用者各自不同的端點必須自行把使用者放進快取鍵。
- 它的最新版本發行於 2024 年 7 月。

## cashews {#cashews}

[cashews](https://github.com/Krukov/cashews) 是非同步 Python 的通用快取工具組,是本頁幾個函式庫中功能最多的。

當你主要快取的是**函式結果**而不是 HTTP 回應,而且需要的不只是 TTL 時,選擇它:

- early 或 soft 提前更新:熱門的鍵在過期前就重新計算,不必讓每個呼叫者都等待快取未命中。
- 標籤:一次讓所有依賴同一筆資料的項目失效。
- 同一套設定中提供速率限制、斷路器、Bloom filter 與鎖。
- Prometheus 指標、Redis Cluster、Redis client-side caching 或磁碟快取。

它的 FastAPI 中介軟體提供 `Cache-Control`、`Age` 與 `ETag` 處理。和這裡的 `@cache` 不同,它們讓用戶端的 `Cache-Control: no-cache` 或 `max-age=0` 略過快取,這在除錯時很方便,但也讓任何用戶端都能把請求直接送到 handler。值預設以 pickle 儲存;如果還有其他人能寫入你的 Redis,請設定 `secret` 讓值經過簽章,或改用 JSON 序列化器。

## aiocache {#aiocache}

[aiocache](https://github.com/aio-libs/aiocache) 是通用的非同步鍵值快取,提供裝飾器(`@cached`、`@cached_stampede`、`@multi_cached`)、可替換的序列化器,以及命中率與計時外掛。它本身沒有 HTTP 或 FastAPI 相關功能。

當你想要一個單純的非同步快取 API,在 FastAPI 之外或搭配任何 web 框架使用,並自行處理 HTTP 標頭時,選擇它。它的最新版本發行於 2024 年 9 月。

## 在應用程式前面放 HTTP 快取或 CDN {#an-http-cache-or-cdn-in-front-of-the-app}

反向 proxy(nginx、Varnish)或 CDN(Cloudflare、Fastly、CloudFront)在請求到達 Python 之前就快取回應。對於**每位訪客都相同的公開回應**,例如首頁、文章或公開的商品列表,這通常是更好的選擇:命中時不佔用任何 worker,快取離用戶端更近,也能吸收原本會打到應用程式伺服器的流量高峰。

以下情況就沒那麼合適:

- 回應取決於請求者是誰。共用快取以 URL(加上 `Vary` 列出的標頭)作為鍵,在那裡把每個使用者的回應分開很容易出錯;而且除非回應明確允許,共用快取不會儲存對帶 `Authorization` 請求的回應。
- 你需要在資料變更的當下,從應用程式碼讓項目失效,而不想呼叫 CDN 的清除(purge)API。
- 你沒有使用 proxy 或 CDN,例如內部 API。

兩者可以並用。`@cache` 會寫出 CDN 讀取的 `Cache-Control` 和 `ETag` 標頭,CDN 負責提供公開路由,`@cache` 則為仍然到達應用程式的請求(邊緣節點尚未快取,或 `no-cache` 重新驗證)保留伺服器端的副本。使用 `public=True` 時要小心:它告訴所有下游快取,即使請求帶有憑證,也可以儲存這個回應。

## 如何選擇 {#which-one-to-choose}

| 你想要…… | 合適的選擇 |
|----------|------------|
| 快取 FastAPI 的 GET 回應,正確處理 `Cache-Control`、`ETag` 與 `304`,並讓每個使用者各自不同的回應不進入共用快取 | FastAPI-CacheX |
| 以最低成本把公開頁面提供給大量訪客 | CDN 或反向 proxy,由 `@cache` 產生它需要的標頭 |
| 快取函式結果,並需要提前更新、標籤、速率限制或指標 | cashews |
| 與框架無關的非同步鍵值快取 | aiocache 或 cashews |
| 保留運作良好的既有 fastapi-cache2 設定 | fastapi-cache2 |
Loading
Loading