aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/middlewares/cache/shared/api-cache.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/middlewares/cache/shared/api-cache.ts')
-rw-r--r--server/middlewares/cache/shared/api-cache.ts45
1 files changed, 41 insertions, 4 deletions
diff --git a/server/middlewares/cache/shared/api-cache.ts b/server/middlewares/cache/shared/api-cache.ts
index 7c366db00..c6197b972 100644
--- a/server/middlewares/cache/shared/api-cache.ts
+++ b/server/middlewares/cache/shared/api-cache.ts
@@ -27,7 +27,13 @@ export class ApiCache {
27 private readonly options: APICacheOptions 27 private readonly options: APICacheOptions
28 private readonly timers: { [ id: string ]: NodeJS.Timeout } = {} 28 private readonly timers: { [ id: string ]: NodeJS.Timeout } = {}
29 29
30 private readonly index: { all: string[] } = { all: [] } 30 private readonly index = {
31 groups: [] as string[],
32 all: [] as string[]
33 }
34
35 // Cache keys per group
36 private groups: { [groupIndex: string]: string[] } = {}
31 37
32 constructor (options: APICacheOptions) { 38 constructor (options: APICacheOptions) {
33 this.options = { 39 this.options = {
@@ -43,7 +49,7 @@ export class ApiCache {
43 49
44 return asyncMiddleware( 50 return asyncMiddleware(
45 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 51 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
46 const key = Redis.Instance.getPrefix() + 'api-cache-' + req.originalUrl 52 const key = this.getCacheKey(req)
47 const redis = Redis.Instance.getClient() 53 const redis = Redis.Instance.getClient()
48 54
49 if (!Redis.Instance.isConnected()) return this.makeResponseCacheable(res, next, key, duration) 55 if (!Redis.Instance.isConnected()) return this.makeResponseCacheable(res, next, key, duration)
@@ -62,6 +68,29 @@ export class ApiCache {
62 ) 68 )
63 } 69 }
64 70
71 clearGroupSafe (group: string) {
72 const run = async () => {
73 const cacheKeys = this.groups[group]
74 if (!cacheKeys) return
75
76 for (const key of cacheKeys) {
77 try {
78 await this.clear(key)
79 } catch (err) {
80 logger.error('Cannot clear ' + key, { err })
81 }
82 }
83
84 delete this.groups[group]
85 }
86
87 void run()
88 }
89
90 private getCacheKey (req: express.Request) {
91 return Redis.Instance.getPrefix() + 'api-cache-' + req.originalUrl
92 }
93
65 private shouldCacheResponse (response: express.Response) { 94 private shouldCacheResponse (response: express.Response) {
66 if (!response) return false 95 if (!response) return false
67 if (this.options.excludeStatus.includes(response.statusCode)) return false 96 if (this.options.excludeStatus.includes(response.statusCode)) return false
@@ -69,8 +98,16 @@ export class ApiCache {
69 return true 98 return true
70 } 99 }
71 100
72 private addIndexEntries (key: string) { 101 private addIndexEntries (key: string, res: express.Response) {
73 this.index.all.unshift(key) 102 this.index.all.unshift(key)
103
104 const groups = res.locals.apicacheGroups || []
105
106 for (const group of groups) {
107 if (!this.groups[group]) this.groups[group] = []
108
109 this.groups[group].push(key)
110 }
74 } 111 }
75 112
76 private filterBlacklistedHeaders (headers: OutgoingHttpHeaders) { 113 private filterBlacklistedHeaders (headers: OutgoingHttpHeaders) {
@@ -177,7 +214,7 @@ export class ApiCache {
177 self.accumulateContent(res, content) 214 self.accumulateContent(res, content)
178 215
179 if (res.locals.apicache.cacheable && res.locals.apicache.content) { 216 if (res.locals.apicache.cacheable && res.locals.apicache.content) {
180 self.addIndexEntries(key) 217 self.addIndexEntries(key, res)
181 218
182 const headers = res.locals.apicache.headers || res.getHeaders() 219 const headers = res.locals.apicache.headers || res.getHeaders()
183 const cacheObject = self.createCacheObject( 220 const cacheObject = self.createCacheObject(