Browse Source

Use apicache instead of our broken implementation

Chocobozzz 7 months ago
parent
commit
47f6409bb8
No account linked to committer's email address
5 changed files with 34 additions and 75 deletions
  1. 2
    1
      package.json
  2. 1
    1
      server/lib/job-queue/job-queue.ts
  3. 10
    2
      server/lib/redis.ts
  4. 8
    65
      server/middlewares/cache.ts
  5. 13
    6
      yarn.lock

+ 2
- 1
package.json View File

@@ -91,9 +91,9 @@
91 91
     "@types/bluebird": "3.5.21"
92 92
   },
93 93
   "dependencies": {
94
+    "apicache": "^1.4.0",
94 95
     "application-config": "^1.0.1",
95 96
     "async": "^2.0.0",
96
-    "async-lock": "^1.1.2",
97 97
     "async-lru": "^1.1.1",
98 98
     "bcrypt": "3.0.5",
99 99
     "bittorrent-tracker": "^9.0.0",
@@ -159,6 +159,7 @@
159 159
     "youtube-dl": "^1.12.2"
160 160
   },
161 161
   "devDependencies": {
162
+    "@types/apicache": "^1.2.0",
162 163
     "@types/async": "^2.0.40",
163 164
     "@types/async-lock": "^1.1.0",
164 165
     "@types/bcrypt": "^3.0.0",

+ 1
- 1
server/lib/job-queue/job-queue.ts View File

@@ -71,7 +71,7 @@ class JobQueue {
71 71
     this.jobRedisPrefix = 'bull-' + WEBSERVER.HOST
72 72
     const queueOptions = {
73 73
       prefix: this.jobRedisPrefix,
74
-      redis: Redis.getRedisClient(),
74
+      redis: Redis.getRedisClientOptions(),
75 75
       settings: {
76 76
         maxStalledCount: 10 // transcoding could be long, so jobs can often be interrupted by restarts
77 77
       }

+ 10
- 2
server/lib/redis.ts View File

@@ -31,7 +31,7 @@ class Redis {
31 31
     if (this.initialized === true) return
32 32
     this.initialized = true
33 33
 
34
-    this.client = createClient(Redis.getRedisClient())
34
+    this.client = createClient(Redis.getRedisClientOptions())
35 35
 
36 36
     this.client.on('error', err => {
37 37
       logger.error('Error in Redis client.', { err })
@@ -45,7 +45,7 @@ class Redis {
45 45
     this.prefix = 'redis-' + WEBSERVER.HOST + '-'
46 46
   }
47 47
 
48
-  static getRedisClient () {
48
+  static getRedisClientOptions () {
49 49
     return Object.assign({},
50 50
       (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {},
51 51
       (CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {},
@@ -55,6 +55,14 @@ class Redis {
55 55
     )
56 56
   }
57 57
 
58
+  getClient () {
59
+    return this.client
60
+  }
61
+
62
+  getPrefix () {
63
+    return this.prefix
64
+  }
65
+
58 66
   /************* Forgot password *************/
59 67
 
60 68
   async setResetPasswordVerificationString (userId: number) {

+ 8
- 65
server/middlewares/cache.ts View File

@@ -1,73 +1,16 @@
1
-import * as express from 'express'
2
-import * as AsyncLock from 'async-lock'
3
-import { parseDurationToMs } from '../helpers/core-utils'
4 1
 import { Redis } from '../lib/redis'
5
-import { logger } from '../helpers/logger'
2
+import * as apicache from 'apicache'
6 3
 
7
-const lock = new AsyncLock({ timeout: 5000 })
4
+// Ensure Redis is initialized
5
+Redis.Instance.init()
8 6
 
9
-function cacheRoute (lifetimeArg: string | number) {
10
-  const lifetime = parseDurationToMs(lifetimeArg)
11
-
12
-  return async function (req: express.Request, res: express.Response, next: express.NextFunction) {
13
-    const redisKey = Redis.Instance.generateCachedRouteKey(req)
14
-
15
-    try {
16
-      await lock.acquire(redisKey, async (done) => {
17
-        const cached = await Redis.Instance.getCachedRoute(req)
18
-
19
-        // Not cached
20
-        if (!cached) {
21
-          logger.debug('No cached results for route %s.', req.originalUrl)
22
-
23
-          const sendSave = res.send.bind(res)
24
-          const redirectSave = res.redirect.bind(res)
25
-
26
-          res.send = (body) => {
27
-            if (res.statusCode >= 200 && res.statusCode < 400) {
28
-              const contentType = res.get('content-type')
29
-
30
-              Redis.Instance.setCachedRoute(req, body, lifetime, contentType, res.statusCode)
31
-                   .then(() => done())
32
-                   .catch(err => {
33
-                     logger.error('Cannot cache route.', { err })
34
-                     return done(err)
35
-                   })
36
-            } else {
37
-              done()
38
-            }
39
-
40
-            return sendSave(body)
41
-          }
42
-
43
-          res.redirect = url => {
44
-            done()
45
-
46
-            return redirectSave(url)
47
-          }
48
-
49
-          return next()
50
-        }
51
-
52
-        if (cached.contentType) res.set('content-type', cached.contentType)
53
-
54
-        if (cached.statusCode) {
55
-          const statusCode = parseInt(cached.statusCode, 10)
56
-          if (!isNaN(statusCode)) res.status(statusCode)
57
-        }
58
-
59
-        logger.debug('Use cached result for %s.', req.originalUrl)
60
-        res.send(cached.body).end()
61
-
62
-        return done()
63
-      })
64
-    } catch (err) {
65
-      logger.error('Cannot serve cached route.', { err })
66
-      return next()
67
-    }
68
-  }
7
+const options = {
8
+  redisClient: Redis.Instance.getClient(),
9
+  appendKey: () => Redis.Instance.getPrefix()
69 10
 }
70 11
 
12
+const cacheRoute = apicache.options(options).middleware
13
+
71 14
 // ---------------------------------------------------------------------------
72 15
 
73 16
 export {

+ 13
- 6
yarn.lock View File

@@ -16,6 +16,13 @@
16 16
   dependencies:
17 17
     any-observable "^0.3.0"
18 18
 
19
+"@types/apicache@^1.2.0":
20
+  version "1.2.0"
21
+  resolved "https://registry.yarnpkg.com/@types/apicache/-/apicache-1.2.0.tgz#5f6e9225e66d22da97042a39ad626b3c158d650d"
22
+  integrity sha512-8uatdizj2GbYHtS4u+x4k2aG1thG6JBWKRidcnauXav+Bxe3bHsWS8HSwcybuLE2q39/95cwb4hkHvqmP7ja2w==
23
+  dependencies:
24
+    "@types/redis" "*"
25
+
19 26
 "@types/async-lock@^1.1.0":
20 27
   version "1.1.1"
21 28
   resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.1.tgz#81f218213bebcc5f740efe9648272c774a2e4b4b"
@@ -276,7 +283,7 @@
276 283
   resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
277 284
   integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
278 285
 
279
-"@types/redis@^2.8.5":
286
+"@types/redis@*", "@types/redis@^2.8.5":
280 287
   version "2.8.12"
281 288
   resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.12.tgz#6405d7ece0d6cc037151b7141cef9ad3cd06f3ac"
282 289
   integrity sha512-eT5cGYr08OnF6OlAHdc2hVOBAKBpfQQNQHsWEvUwRPFiXRd+vv+hOHSSIo4xB7M5vZOZdjMT2OUlXYqo3YlIGQ==
@@ -548,6 +555,11 @@ anymatch@^2.0.0:
548 555
     micromatch "^3.1.4"
549 556
     normalize-path "^2.1.1"
550 557
 
558
+apicache@^1.4.0:
559
+  version "1.4.0"
560
+  resolved "https://registry.yarnpkg.com/apicache/-/apicache-1.4.0.tgz#3835fbe18717caca3a44cb6272d49b52cac30d3a"
561
+  integrity sha512-pX/Sf9q9HNzAC5F+hPgxt8v3eQVZkXL/+8HpAnrDJXFmma80F2aHAAeWTql3BsG87lc3T6A7CFPNWMTl97L/7Q==
562
+
551 563
 append-field@^1.0.0:
552 564
   version "1.0.0"
553 565
   resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
@@ -695,11 +707,6 @@ async-limiter@~1.0.0:
695 707
   resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
696 708
   integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
697 709
 
698
-async-lock@^1.1.2:
699
-  version "1.2.0"
700
-  resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.2.0.tgz#cd6a53cb1ec3f86af25eafdeb6bc7c6e317258b8"
701
-  integrity sha512-81HzTQm4+qMj6PwNlnR+y9g7pDdGGzd/YBUrQnHk+BhR28ja2qv497NkQQc1KcKEqh/RShm07di2b0cIWVFrNQ==
702
-
703 710
 async-lru@^1.1.1:
704 711
   version "1.1.2"
705 712
   resolved "https://registry.yarnpkg.com/async-lru/-/async-lru-1.1.2.tgz#abe831f3a52123c87d44273615e203b1ef04692e"

Loading…
Cancel
Save