Skip to content
Draft
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
16 changes: 16 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ jobs:

- run: pnpm run test:cluster:live

# The v2/v3 storage layout again, with both backends on their cluster
# code paths and the entries spread over every master. See
# https://github.com/strapi-community/plugin-rest-cache/pull/239
- run: pnpm run test:continuity
env:
REDIS_CLUSTER_NODES: 127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002

linters:
runs-on: ubuntu-latest
strategy:
Expand Down Expand Up @@ -269,3 +276,12 @@ jobs:
run: pnpm run test:redis:live
env:
REDIS_URL: redis://127.0.0.1:6379/15

# The provider's plugin-redis v2 and v3 backends must share one storage
# layout, or an upgrade orphans every entry cached before it. Needs a
# real Redis, so it runs here rather than in provider_smoke. See
# https://github.com/strapi-community/plugin-rest-cache/pull/239
- name: Check v2/v3 key continuity
run: pnpm run test:continuity
env:
REDIS_URL: redis://127.0.0.1:6379/15
22 changes: 16 additions & 6 deletions docs/guide/providers/redis.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,10 @@ The plugin passes an explicit lifetime on every write, taken from `strategy.maxA

### Other options

Anything else in `options` is forwarded to [`@keyv/redis`](https://github.com/jaredwray/keyv/tree/main/packages/redis#options) untouched — `namespace`, `useRedisSets`, and so on.
On plugin-redis v2, anything else in `options` is forwarded to [`@keyv/redis`](https://github.com/jaredwray/keyv/tree/main/packages/redis#options) untouched — `namespace`, `useRedisSets`, and so on. On [plugin-redis v3](#plugin-redis-v3) the provider runs on its own store, which honours `useRedisSets` and ignores the rest.

::: warning
Leave `useRedisSets` enabled. The provider relies on the key-tracking set that `@keyv/redis` maintains, both to enumerate keys efficiently and to purge correctly on a cluster. With it disabled the provider falls back to `SCAN`, which is far slower and, on a cluster, incomplete — see below.
Leave `useRedisSets` enabled. The provider lists keys for every pattern purge, and with the key-tracking set that is a single `SMEMBERS`. With it disabled there is no set to read, so the provider finds its entries with `SCAN` instead — on every master of a cluster, so purges are still complete, but each listing walks the whole keyspace of every node, which is far slower on a large or shared database.
:::

## Key prefixes
Expand Down Expand Up @@ -239,11 +239,21 @@ Two things differ when clustered, and both are handled for you:

Without a `MULTI`, a purge and a response being cached for the same key can interleave, so the provider removes a key from the tracking set _before_ deleting the entry. The other way round, a write landing between the two left a live entry outside the set, which no purge could find until it expired. The trade-off is on the failure path: if Redis fails the delete after the entry has been untracked, the entry stays cached, out of reach of purges, until its `maxAge`.

- **Key listing does not use `SCAN`.** `SCAN` addresses one node, so on a cluster it returns only the portion of the keyspace that node holds — a purge built on it silently misses everything on the other nodes. Reading the tracking set avoids that entirely, because the set is one key and therefore complete.
- **Key listing reads the tracking set.** The set is one key, and therefore complete wherever it lives. `SCAN` addresses one node, so on a cluster it returns only the portion of the keyspace that node holds.

::: warning
This is the concrete reason not to disable `useRedisSets` on a cluster: doing so drops the provider onto the `SCAN` fallback, and purges will quietly under-delete.
:::
With `useRedisSets` disabled there is no set, so the provider sends `SCAN` to every master and combines the results ([#245](https://github.com/strapi-community/plugin-rest-cache/pull/245)). Purges are complete either way; the tracking set is just much cheaper to read.

## plugin-redis v3

[`@strapi-community/plugin-redis`](https://github.com/strapi-community/plugin-redis) v3 moves from ioredis to node-redis. The provider supports v2 and v3 alike — its peer range is `^2.0.0 || ^3.0.0-0` — and needs no configuration change for either:

- **Detection.** The provider checks for v3's `connection` service at bootstrap, by what it can do rather than by version number. If it is there, the provider waits on `whenReady(connection)`, which rejects with the reason rather than hanging when the connection cannot be established. Otherwise it runs exactly as on v2.
- **Client.** On v3 the provider runs on the connection's node-redis client, `.native`. v3 also offers an ioredis-compatible `.client`, but that is deprecated and removed in v4, so the provider only keeps it on `provider.client` for code typed against it and never sends a command through it.
- **Client swap.** v3 replaces the node-redis client of a cluster or sentinel connection that has to reconnect from scratch. The provider reads `.native` for every command instead of keeping the client it started with, so it follows the swap.
- **Same data.** Entries are stored exactly as on v2 — the same key names, the same tracking set, lifetimes in milliseconds — so entries cached before an upgrade are still read and purged after it, and after a rollback. Cluster deletes, key listing without `useRedisSets` and the tracking-set prune behave as described above.
- **Shared connection.** The client belongs to the redis plugin and other plugins may use it. The provider never closes it.

Node.js 20 is not supported by plugin-redis v3. On Node 20, stay on plugin-redis v2: the provider keeps working on it as before.

## KeyDB

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"docs:build:only": "vitepress build docs",
"build:providers": "pnpm --filter \"./packages/provider-*\" run build",
"test:cluster:live": "node scripts/redis-cluster-live.cjs",
"test:redis:live": "node scripts/redis-standalone-live.cjs"
"test:redis:live": "node scripts/redis-standalone-live.cjs",
"test:continuity": "node scripts/redis-key-continuity.cjs"
},
"license": "MIT",
"devDependencies": {
Expand Down
5 changes: 4 additions & 1 deletion packages/provider-rest-cache-redis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,19 @@
"keyv": "^5.5.0"
},
"devDependencies": {
"@redis/client": "^6.3.0",
"@strapi-community/plugin-redis": "^2.0.0",
"@strapi-community/plugin-rest-cache": "workspace:*",
"@types/node": "^26.2.0",
"ioredis": "^5.11.1",
"npm-run-all": "^4.1.5",
"prettier": "^3.9.6",
"typescript": "^5.9.3"
},
"peerDependencies": {
"@strapi-community/plugin-rest-cache": "workspace:^",
"@strapi/strapi": "^5.0.0"
"@strapi/strapi": "^5.0.0",
"@strapi-community/plugin-redis": "^2.0.0 || ^3.0.0-0"
},
"engines": {
"node": ">=20.0.0 <=26.x.x"
Expand Down
Loading
Loading