strapi-cache 1.8.3 → 1.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -35,9 +35,31 @@ or
|
|
|
35
35
|
yarn add strapi-cache
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Quickstart
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
// config/plugins.{js,ts}
|
|
42
|
+
'strapi-cache': {
|
|
43
|
+
enabled: true,
|
|
44
|
+
},
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
To use **Redis** or **Valkey** instead of memory, set `provider` and `redisConfig` (required for those providers):
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
// config/plugins.{js,ts}
|
|
51
|
+
'strapi-cache': {
|
|
52
|
+
enabled: true,
|
|
53
|
+
config: {
|
|
54
|
+
provider: 'redis', // or 'valkey'
|
|
55
|
+
redisConfig: env('REDIS_URL', 'redis://127.0.0.1:6379'),
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
See [ioredis](https://github.com/redis/ioredis) (Redis) or [iovalkey](https://github.com/valkey-io/iovalkey) (Valkey) for advanced `redisConfig` shapes (URL string or client options object).
|
|
39
61
|
|
|
40
|
-
|
|
62
|
+
Full configuration example:
|
|
41
63
|
|
|
42
64
|
```javascript
|
|
43
65
|
// config/plugins.{js,ts}
|
|
@@ -51,7 +73,7 @@ In your Strapi project, navigate to `config/plugins.js` and add the following co
|
|
|
51
73
|
allowStale: false, // Allow stale cache items (only for memory cache)
|
|
52
74
|
cacheableRoutes: ['/api/products', '/api/categories'], // Caches routes which start with these paths (if empty array, all '/api' routes are cached)
|
|
53
75
|
// cacheableEntities: ['products', 'categories'], // (Optional) Specify which entities to cache. When set, only these entities will be cached (ignores cacheableRoutes). If not set (undefined), cacheableRoutes logic is used
|
|
54
|
-
excludeRoutes: ['/api/products/private'], //
|
|
76
|
+
excludeRoutes: ['/api/products/private'], // Exclude routes which start with these paths from being cached (takes precedence over cacheableRoutes). **Note:** `excludeRoutes` takes precedence over `cacheableRoutes`.
|
|
55
77
|
provider: 'memory', // Cache provider ('memory', 'redis' or 'valkey')
|
|
56
78
|
redisConfig: env('REDIS_URL', 'redis://localhost:6379'), // Redis/Valkey config: string or object. See https://github.com/redis/ioredis (Redis) or https://github.com/valkey-io/iovalkey (Valkey)
|
|
57
79
|
redisClusterNodes: [], // If provided any cluster node (this list is not empty), initialize cluster client. Each object must have keys 'host' and 'port'
|
|
@@ -70,6 +92,36 @@ In your Strapi project, navigate to `config/plugins.js` and add the following co
|
|
|
70
92
|
},
|
|
71
93
|
```
|
|
72
94
|
|
|
95
|
+
## ⚙️ Configuration
|
|
96
|
+
|
|
97
|
+
Possible configuration keys are listed below; omitted keys keep the plugin defaults.
|
|
98
|
+
|
|
99
|
+
| Key | Description | Possible values |
|
|
100
|
+
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
101
|
+
| `debug` | Log cache decisions and operations to the server console | `true` or `false` (default: `false`) |
|
|
102
|
+
| `provider` | Where entries are stored | `'memory'`, `'redis'`, or `'valkey'` (default: `'memory'`) |
|
|
103
|
+
| `redisConfig` | Redis/Valkey connection: URL string or client options passed to ioredis/iovalkey | String or object; **required** when `provider` is `'redis'` or `'valkey'`. Default: value of `REDIS_URL` from the environment |
|
|
104
|
+
| `redisClusterNodes` | Seed nodes for Redis cluster mode; non-empty list switches to a cluster client | Array of `{ host: string, port: number }` (default: `[]`) |
|
|
105
|
+
| `redisClusterOptions` | Options for the cluster client (e.g. `scaleReads`); `redisOptions` often come from `redisConfig` | Object (default: `{}`) |
|
|
106
|
+
| `redisScanDeleteCount` | `COUNT` hint for `SCAN` when purging keys (Redis/Valkey) | Positive number (default: `100`) |
|
|
107
|
+
| `max` | Maximum number of entries (in-memory provider only) | Positive integer (default: `1000`) |
|
|
108
|
+
| `ttl` | Time-to-live for each entry, in milliseconds | Non-negative number (default: `3600000`, i.e. 1 hour) |
|
|
109
|
+
| `size` | Approximate max total size in bytes (in-memory provider only) | Positive integer (default: `10485760`, i.e. 10 MB) |
|
|
110
|
+
| `allowStale` | Whether stale entries may be returned (in-memory provider only) | `true` or `false` (default: `false`) |
|
|
111
|
+
| `cacheableRoutes` | Only URLs starting with one of these paths are cached; if empty, every URL under the REST API prefix matches | Array of path prefix strings (default: `[]` meaning “all API routes”) |
|
|
112
|
+
| `cacheableEntities` | If non-empty, only these API “entity” segments are cached; **when set, this drives eligibility instead of** `cacheableRoutes` | Array of strings (e.g. collection/table names), or omit / leave empty to use `cacheableRoutes` |
|
|
113
|
+
| `excludeRoutes` | URLs starting with any of these prefixes are **never** cached; evaluated before `cacheableRoutes` / entities | Array of path prefix strings (default: `[]`) |
|
|
114
|
+
| `cacheHeaders` | Store and replay response headers with the body | `true` or `false` (default: `true`) |
|
|
115
|
+
| `cacheHeadersDenyList` | Header names (lowercase) to strip when `cacheHeaders` is `true` | Array of strings (default: `[]`) |
|
|
116
|
+
| `cacheHeadersAllowList` | If non-empty, only these header names (lowercase) are stored; if empty, all headers are stored (subject to deny list) | Array of strings (default: `[]`) |
|
|
117
|
+
| `cacheAuthorizedRequests` | Whether to cache requests that include an `Authorization` header | `true` or `false` (default: `false`) |
|
|
118
|
+
| `cacheGetTimeoutInMs` | Max time to wait for a cache read before treating it as a miss | Milliseconds (default: `1000`) |
|
|
119
|
+
| `autoPurgeCache` | Invalidate relevant REST cache entries after content create/update/delete | `true` or `false` (default: `true`) |
|
|
120
|
+
| `autoPurgeGraphQL` | Invalidate GraphQL cache after content create/update/delete | `true` or `false` (default: `false` if omitted; set `true` to enable) |
|
|
121
|
+
| `autoPurgeCacheOnStart` | Clear the cache when Strapi starts | `true` or `false` (default: `true`) |
|
|
122
|
+
| `disableAdminPopups` | Turn off admin UI notifications for cache actions | `true` or `false` (default: `false`) |
|
|
123
|
+
| `disableAdminButtons` | Hide manual purge controls in the admin (list and edit views) | `true` or `false` (default: `false`) |
|
|
124
|
+
|
|
73
125
|
## 🔍 Routes
|
|
74
126
|
|
|
75
127
|
The plugin creates three new routes
|
|
@@ -85,7 +137,7 @@ All of these routes are protected by the policies `admin::isAuthenticatedAdmin`
|
|
|
85
137
|
|
|
86
138
|
- **Storage**: The plugin keeps cached data in memory, Redis or Valkey, depending on the configuration.
|
|
87
139
|
- **Packages**: Uses [lru-cache](https://github.com/isaacs/node-lru-cache) for in-memory cache. Uses [ioredis](https://github.com/redis/ioredis) for Redis and [iovalkey](https://github.com/valkey-io/iovalkey) for Valkey caching.
|
|
88
|
-
- **Automatic Invalidation**:
|
|
140
|
+
- **Automatic Invalidation**: When `autoPurgeCache` is enabled (default), relevant REST cache entries are invalidated on content create, update, or delete. When `autoPurgeGraphQL` is enabled, GraphQL cache is invalidated the same way (it is off unless you set it in config).
|
|
89
141
|
- **`no-cache` Header Support**: Respects the `no-cache` header, letting you skip the cache by setting `Cache-Control: no-cache` in your request.
|
|
90
142
|
- **Default Cached Requests**: By default, caches all GET requests to `/api` (or whatever prefix you defined) and POST requests to `/graphql`. You can customize which routes or entities to cache using `cacheableRoutes` or `cacheableEntities` config options.
|
|
91
143
|
|
package/dist/server/index.js
CHANGED
|
@@ -5,7 +5,6 @@ const zlib = require("zlib");
|
|
|
5
5
|
const rawBody = require("raw-body");
|
|
6
6
|
const lruCache = require("lru-cache");
|
|
7
7
|
const ioredis = require("ioredis");
|
|
8
|
-
const iovalkey = require("iovalkey");
|
|
9
8
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
10
9
|
const Stream__default = /* @__PURE__ */ _interopDefault(Stream);
|
|
11
10
|
const rawBody__default = /* @__PURE__ */ _interopDefault(rawBody);
|
|
@@ -274,6 +273,9 @@ const middleware$1 = async (ctx, next) => {
|
|
|
274
273
|
if (cacheEntry && !noCache) {
|
|
275
274
|
loggy.info(`HIT with key: ${key}`);
|
|
276
275
|
ctx.status = 200;
|
|
276
|
+
if (cacheEntry?.body?.type === "Buffer" && Array.isArray(cacheEntry.body.data)) {
|
|
277
|
+
cacheEntry.body = Buffer.from(cacheEntry.body.data);
|
|
278
|
+
}
|
|
277
279
|
ctx.body = cacheEntry.body;
|
|
278
280
|
if (cacheHeaders) {
|
|
279
281
|
ctx.set(cacheEntry.headers);
|
|
@@ -544,7 +546,8 @@ const config = {
|
|
|
544
546
|
autoPurgeCache: true,
|
|
545
547
|
autoPurgeCacheOnStart: true,
|
|
546
548
|
disableAdminPopups: false,
|
|
547
|
-
disableAdminButtons: false
|
|
549
|
+
disableAdminButtons: false,
|
|
550
|
+
redisScanDeleteCount: 100
|
|
548
551
|
}),
|
|
549
552
|
validator: (config2) => {
|
|
550
553
|
if (typeof config2.debug !== "boolean") {
|
|
@@ -624,6 +627,9 @@ const config = {
|
|
|
624
627
|
if (typeof config2.disableAdminButtons !== "boolean") {
|
|
625
628
|
throw new Error(`Invalid config: disableAdminButtons must be a boolean`);
|
|
626
629
|
}
|
|
630
|
+
if (typeof config2.redisScanDeleteCount !== "number") {
|
|
631
|
+
throw new Error(`Invalid config: redisScanDeleteCount must be a number`);
|
|
632
|
+
}
|
|
627
633
|
}
|
|
628
634
|
};
|
|
629
635
|
const contentTypes = {};
|
|
@@ -856,34 +862,20 @@ class RedisCacheProvider {
|
|
|
856
862
|
this.strapi.plugin("strapi-cache").config("cacheGetTimeoutInMs")
|
|
857
863
|
);
|
|
858
864
|
this.keyPrefix = this.strapi.plugin("strapi-cache").config("redisConfig")?.["keyPrefix"] ?? "";
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
this.client = new iovalkey.Cluster(
|
|
867
|
-
redisClusterNodes,
|
|
868
|
-
clusterOptions
|
|
869
|
-
);
|
|
870
|
-
} else {
|
|
871
|
-
this.client = new iovalkey.Redis(redisConfig);
|
|
865
|
+
this.redisScanDeleteCount = Number(
|
|
866
|
+
this.strapi.plugin("strapi-cache").config("redisScanDeleteCount")
|
|
867
|
+
);
|
|
868
|
+
if (redisClusterNodes.length) {
|
|
869
|
+
const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions");
|
|
870
|
+
if (!redisClusterOptions["redisOptions"]) {
|
|
871
|
+
redisClusterOptions.redisOptions = redisConfig;
|
|
872
872
|
}
|
|
873
|
-
|
|
873
|
+
this.client = new ioredis.Redis.Cluster(redisClusterNodes, redisClusterOptions);
|
|
874
874
|
} else {
|
|
875
|
-
|
|
876
|
-
const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions");
|
|
877
|
-
if (!redisClusterOptions["redisOptions"]) {
|
|
878
|
-
redisClusterOptions.redisOptions = redisConfig;
|
|
879
|
-
}
|
|
880
|
-
this.client = new ioredis.Redis.Cluster(redisClusterNodes, redisClusterOptions);
|
|
881
|
-
} else {
|
|
882
|
-
this.client = new ioredis.Redis(redisConfig);
|
|
883
|
-
}
|
|
884
|
-
loggy.info("Redis provider initialized");
|
|
875
|
+
this.client = new ioredis.Redis(redisConfig);
|
|
885
876
|
}
|
|
886
877
|
this.initialized = true;
|
|
878
|
+
loggy.info(`${provider === "valkey" ? "Valkey" : "Redis"} provider initialized`);
|
|
887
879
|
} catch (error) {
|
|
888
880
|
loggy.error(error);
|
|
889
881
|
}
|
|
@@ -931,18 +923,6 @@ class RedisCacheProvider {
|
|
|
931
923
|
return null;
|
|
932
924
|
}
|
|
933
925
|
}
|
|
934
|
-
/**
|
|
935
|
-
* Deletes all given keys in Redis pipeline.
|
|
936
|
-
* @param keys to delete from cache
|
|
937
|
-
*/
|
|
938
|
-
async delAll(keys) {
|
|
939
|
-
const pipeline = this.client.pipeline();
|
|
940
|
-
keys.forEach((key) => {
|
|
941
|
-
const relativeKey = key.slice(this.keyPrefix.length);
|
|
942
|
-
pipeline.del(relativeKey);
|
|
943
|
-
});
|
|
944
|
-
await pipeline.exec();
|
|
945
|
-
}
|
|
946
926
|
async keys() {
|
|
947
927
|
if (!this.ready) return null;
|
|
948
928
|
try {
|
|
@@ -972,13 +952,37 @@ class RedisCacheProvider {
|
|
|
972
952
|
return null;
|
|
973
953
|
}
|
|
974
954
|
}
|
|
955
|
+
async deleteBatch(client, batch, regExps) {
|
|
956
|
+
const toDelete = batch.filter((key) => regExps.some((re) => re.test(key)));
|
|
957
|
+
if (toDelete.length === 0) return;
|
|
958
|
+
const pipeline = client.pipeline();
|
|
959
|
+
for (const key of toDelete) {
|
|
960
|
+
const relativeKey = key.startsWith(this.keyPrefix) ? key.slice(this.keyPrefix.length) : key;
|
|
961
|
+
pipeline.del(relativeKey);
|
|
962
|
+
}
|
|
963
|
+
await pipeline.exec();
|
|
964
|
+
}
|
|
965
|
+
scanAndDelete(client, regExps) {
|
|
966
|
+
return new Promise((resolve, reject) => {
|
|
967
|
+
const stream = client.scanStream({ match: `${this.keyPrefix}*`, count: this.redisScanDeleteCount });
|
|
968
|
+
stream.on("data", (batch) => {
|
|
969
|
+
stream.pause();
|
|
970
|
+
this.deleteBatch(client, batch, regExps).then(() => stream.resume()).catch(reject);
|
|
971
|
+
});
|
|
972
|
+
stream.on("end", resolve);
|
|
973
|
+
stream.on("error", reject);
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* ScanStream keys and batch delete for Redis,
|
|
978
|
+
* iterates over master nodes in case of Cluster.
|
|
979
|
+
*/
|
|
975
980
|
async clearByRegexp(regExps) {
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
return;
|
|
981
|
+
if (this.client instanceof ioredis.Redis) {
|
|
982
|
+
return this.scanAndDelete(this.client, regExps);
|
|
979
983
|
}
|
|
980
|
-
const
|
|
981
|
-
await this.
|
|
984
|
+
const nodes = this.client.nodes("master");
|
|
985
|
+
await Promise.all(nodes.map((node) => this.scanAndDelete(node, regExps)));
|
|
982
986
|
}
|
|
983
987
|
}
|
|
984
988
|
const resolveCacheProvider = (strapi2) => {
|
package/dist/server/index.mjs
CHANGED
|
@@ -3,8 +3,7 @@ import Stream, { Readable } from "stream";
|
|
|
3
3
|
import { createInflate, createBrotliDecompress, createGunzip } from "zlib";
|
|
4
4
|
import rawBody from "raw-body";
|
|
5
5
|
import { LRUCache } from "lru-cache";
|
|
6
|
-
import { Redis
|
|
7
|
-
import { Cluster, Redis } from "iovalkey";
|
|
6
|
+
import { Redis } from "ioredis";
|
|
8
7
|
const loggy = {
|
|
9
8
|
info: (msg) => {
|
|
10
9
|
const shouldDebug = strapi.plugin("strapi-cache").config("debug") ?? false;
|
|
@@ -270,6 +269,9 @@ const middleware$1 = async (ctx, next) => {
|
|
|
270
269
|
if (cacheEntry && !noCache) {
|
|
271
270
|
loggy.info(`HIT with key: ${key}`);
|
|
272
271
|
ctx.status = 200;
|
|
272
|
+
if (cacheEntry?.body?.type === "Buffer" && Array.isArray(cacheEntry.body.data)) {
|
|
273
|
+
cacheEntry.body = Buffer.from(cacheEntry.body.data);
|
|
274
|
+
}
|
|
273
275
|
ctx.body = cacheEntry.body;
|
|
274
276
|
if (cacheHeaders) {
|
|
275
277
|
ctx.set(cacheEntry.headers);
|
|
@@ -540,7 +542,8 @@ const config = {
|
|
|
540
542
|
autoPurgeCache: true,
|
|
541
543
|
autoPurgeCacheOnStart: true,
|
|
542
544
|
disableAdminPopups: false,
|
|
543
|
-
disableAdminButtons: false
|
|
545
|
+
disableAdminButtons: false,
|
|
546
|
+
redisScanDeleteCount: 100
|
|
544
547
|
}),
|
|
545
548
|
validator: (config2) => {
|
|
546
549
|
if (typeof config2.debug !== "boolean") {
|
|
@@ -620,6 +623,9 @@ const config = {
|
|
|
620
623
|
if (typeof config2.disableAdminButtons !== "boolean") {
|
|
621
624
|
throw new Error(`Invalid config: disableAdminButtons must be a boolean`);
|
|
622
625
|
}
|
|
626
|
+
if (typeof config2.redisScanDeleteCount !== "number") {
|
|
627
|
+
throw new Error(`Invalid config: redisScanDeleteCount must be a number`);
|
|
628
|
+
}
|
|
623
629
|
}
|
|
624
630
|
};
|
|
625
631
|
const contentTypes = {};
|
|
@@ -852,34 +858,20 @@ class RedisCacheProvider {
|
|
|
852
858
|
this.strapi.plugin("strapi-cache").config("cacheGetTimeoutInMs")
|
|
853
859
|
);
|
|
854
860
|
this.keyPrefix = this.strapi.plugin("strapi-cache").config("redisConfig")?.["keyPrefix"] ?? "";
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
this.client = new Cluster(
|
|
863
|
-
redisClusterNodes,
|
|
864
|
-
clusterOptions
|
|
865
|
-
);
|
|
866
|
-
} else {
|
|
867
|
-
this.client = new Redis(redisConfig);
|
|
861
|
+
this.redisScanDeleteCount = Number(
|
|
862
|
+
this.strapi.plugin("strapi-cache").config("redisScanDeleteCount")
|
|
863
|
+
);
|
|
864
|
+
if (redisClusterNodes.length) {
|
|
865
|
+
const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions");
|
|
866
|
+
if (!redisClusterOptions["redisOptions"]) {
|
|
867
|
+
redisClusterOptions.redisOptions = redisConfig;
|
|
868
868
|
}
|
|
869
|
-
|
|
869
|
+
this.client = new Redis.Cluster(redisClusterNodes, redisClusterOptions);
|
|
870
870
|
} else {
|
|
871
|
-
|
|
872
|
-
const redisClusterOptions = this.strapi.plugin("strapi-cache").config("redisClusterOptions");
|
|
873
|
-
if (!redisClusterOptions["redisOptions"]) {
|
|
874
|
-
redisClusterOptions.redisOptions = redisConfig;
|
|
875
|
-
}
|
|
876
|
-
this.client = new Redis$1.Cluster(redisClusterNodes, redisClusterOptions);
|
|
877
|
-
} else {
|
|
878
|
-
this.client = new Redis$1(redisConfig);
|
|
879
|
-
}
|
|
880
|
-
loggy.info("Redis provider initialized");
|
|
871
|
+
this.client = new Redis(redisConfig);
|
|
881
872
|
}
|
|
882
873
|
this.initialized = true;
|
|
874
|
+
loggy.info(`${provider === "valkey" ? "Valkey" : "Redis"} provider initialized`);
|
|
883
875
|
} catch (error) {
|
|
884
876
|
loggy.error(error);
|
|
885
877
|
}
|
|
@@ -927,18 +919,6 @@ class RedisCacheProvider {
|
|
|
927
919
|
return null;
|
|
928
920
|
}
|
|
929
921
|
}
|
|
930
|
-
/**
|
|
931
|
-
* Deletes all given keys in Redis pipeline.
|
|
932
|
-
* @param keys to delete from cache
|
|
933
|
-
*/
|
|
934
|
-
async delAll(keys) {
|
|
935
|
-
const pipeline = this.client.pipeline();
|
|
936
|
-
keys.forEach((key) => {
|
|
937
|
-
const relativeKey = key.slice(this.keyPrefix.length);
|
|
938
|
-
pipeline.del(relativeKey);
|
|
939
|
-
});
|
|
940
|
-
await pipeline.exec();
|
|
941
|
-
}
|
|
942
922
|
async keys() {
|
|
943
923
|
if (!this.ready) return null;
|
|
944
924
|
try {
|
|
@@ -968,13 +948,37 @@ class RedisCacheProvider {
|
|
|
968
948
|
return null;
|
|
969
949
|
}
|
|
970
950
|
}
|
|
951
|
+
async deleteBatch(client, batch, regExps) {
|
|
952
|
+
const toDelete = batch.filter((key) => regExps.some((re) => re.test(key)));
|
|
953
|
+
if (toDelete.length === 0) return;
|
|
954
|
+
const pipeline = client.pipeline();
|
|
955
|
+
for (const key of toDelete) {
|
|
956
|
+
const relativeKey = key.startsWith(this.keyPrefix) ? key.slice(this.keyPrefix.length) : key;
|
|
957
|
+
pipeline.del(relativeKey);
|
|
958
|
+
}
|
|
959
|
+
await pipeline.exec();
|
|
960
|
+
}
|
|
961
|
+
scanAndDelete(client, regExps) {
|
|
962
|
+
return new Promise((resolve, reject) => {
|
|
963
|
+
const stream = client.scanStream({ match: `${this.keyPrefix}*`, count: this.redisScanDeleteCount });
|
|
964
|
+
stream.on("data", (batch) => {
|
|
965
|
+
stream.pause();
|
|
966
|
+
this.deleteBatch(client, batch, regExps).then(() => stream.resume()).catch(reject);
|
|
967
|
+
});
|
|
968
|
+
stream.on("end", resolve);
|
|
969
|
+
stream.on("error", reject);
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* ScanStream keys and batch delete for Redis,
|
|
974
|
+
* iterates over master nodes in case of Cluster.
|
|
975
|
+
*/
|
|
971
976
|
async clearByRegexp(regExps) {
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
return;
|
|
977
|
+
if (this.client instanceof Redis) {
|
|
978
|
+
return this.scanAndDelete(this.client, regExps);
|
|
975
979
|
}
|
|
976
|
-
const
|
|
977
|
-
await this.
|
|
980
|
+
const nodes = this.client.nodes("master");
|
|
981
|
+
await Promise.all(nodes.map((node) => this.scanAndDelete(node, regExps)));
|
|
978
982
|
}
|
|
979
983
|
}
|
|
980
984
|
const resolveCacheProvider = (strapi2) => {
|
|
@@ -6,18 +6,20 @@ export declare class RedisCacheProvider implements CacheProvider {
|
|
|
6
6
|
private client;
|
|
7
7
|
private cacheGetTimeoutInMs;
|
|
8
8
|
private keyPrefix;
|
|
9
|
+
private redisScanDeleteCount;
|
|
9
10
|
constructor(strapi: Core.Strapi);
|
|
10
11
|
init(): void;
|
|
11
12
|
get ready(): boolean;
|
|
12
13
|
get(key: string): Promise<any | null>;
|
|
13
14
|
set(key: string, val: any): Promise<any | null>;
|
|
14
15
|
del(key: string): Promise<any | null>;
|
|
15
|
-
/**
|
|
16
|
-
* Deletes all given keys in Redis pipeline.
|
|
17
|
-
* @param keys to delete from cache
|
|
18
|
-
*/
|
|
19
|
-
delAll(keys: string[]): Promise<void>;
|
|
20
16
|
keys(): Promise<string[] | null>;
|
|
21
17
|
reset(): Promise<any | null>;
|
|
18
|
+
private deleteBatch;
|
|
19
|
+
private scanAndDelete;
|
|
20
|
+
/**
|
|
21
|
+
* ScanStream keys and batch delete for Redis,
|
|
22
|
+
* iterates over master nodes in case of Cluster.
|
|
23
|
+
*/
|
|
22
24
|
clearByRegexp(regExps: RegExp[]): Promise<void>;
|
|
23
25
|
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.8.
|
|
2
|
+
"version": "1.8.8",
|
|
3
3
|
"keywords": [
|
|
4
4
|
"strapi cache",
|
|
5
5
|
"strapi rest cache",
|
|
@@ -42,7 +42,6 @@
|
|
|
42
42
|
"@strapi/design-system": "^2.0.1",
|
|
43
43
|
"@strapi/icons": "^2.0.1",
|
|
44
44
|
"ioredis": "^5.6.1",
|
|
45
|
-
"iovalkey": "^0.3.3",
|
|
46
45
|
"lru-cache": "^11.1.0",
|
|
47
46
|
"raw-body": "^3.0.0",
|
|
48
47
|
"react-intl": "^7.1.10"
|