aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--package.json3
-rw-r--r--server/lib/job-queue/job-queue.ts2
-rw-r--r--server/lib/redis.ts12
-rw-r--r--server/middlewares/cache.ts73
-rw-r--r--yarn.lock19
5 files changed, 34 insertions, 75 deletions
diff --git a/package.json b/package.json
index 41a040c59..1630706eb 100644
--- a/package.json
+++ b/package.json
@@ -91,9 +91,9 @@
91 "@types/bluebird": "3.5.21" 91 "@types/bluebird": "3.5.21"
92 }, 92 },
93 "dependencies": { 93 "dependencies": {
94 "apicache": "^1.4.0",
94 "application-config": "^1.0.1", 95 "application-config": "^1.0.1",
95 "async": "^2.0.0", 96 "async": "^2.0.0",
96 "async-lock": "^1.1.2",
97 "async-lru": "^1.1.1", 97 "async-lru": "^1.1.1",
98 "bcrypt": "3.0.5", 98 "bcrypt": "3.0.5",
99 "bittorrent-tracker": "^9.0.0", 99 "bittorrent-tracker": "^9.0.0",
@@ -159,6 +159,7 @@
159 "youtube-dl": "^1.12.2" 159 "youtube-dl": "^1.12.2"
160 }, 160 },
161 "devDependencies": { 161 "devDependencies": {
162 "@types/apicache": "^1.2.0",
162 "@types/async": "^2.0.40", 163 "@types/async": "^2.0.40",
163 "@types/async-lock": "^1.1.0", 164 "@types/async-lock": "^1.1.0",
164 "@types/bcrypt": "^3.0.0", 165 "@types/bcrypt": "^3.0.0",
diff --git a/server/lib/job-queue/job-queue.ts b/server/lib/job-queue/job-queue.ts
index f09eb6ff1..3c810da98 100644
--- a/server/lib/job-queue/job-queue.ts
+++ b/server/lib/job-queue/job-queue.ts
@@ -71,7 +71,7 @@ class JobQueue {
71 this.jobRedisPrefix = 'bull-' + WEBSERVER.HOST 71 this.jobRedisPrefix = 'bull-' + WEBSERVER.HOST
72 const queueOptions = { 72 const queueOptions = {
73 prefix: this.jobRedisPrefix, 73 prefix: this.jobRedisPrefix,
74 redis: Redis.getRedisClient(), 74 redis: Redis.getRedisClientOptions(),
75 settings: { 75 settings: {
76 maxStalledCount: 10 // transcoding could be long, so jobs can often be interrupted by restarts 76 maxStalledCount: 10 // transcoding could be long, so jobs can often be interrupted by restarts
77 } 77 }
diff --git a/server/lib/redis.ts b/server/lib/redis.ts
index b4044bf0f..f77d0b62c 100644
--- a/server/lib/redis.ts
+++ b/server/lib/redis.ts
@@ -31,7 +31,7 @@ class Redis {
31 if (this.initialized === true) return 31 if (this.initialized === true) return
32 this.initialized = true 32 this.initialized = true
33 33
34 this.client = createClient(Redis.getRedisClient()) 34 this.client = createClient(Redis.getRedisClientOptions())
35 35
36 this.client.on('error', err => { 36 this.client.on('error', err => {
37 logger.error('Error in Redis client.', { err }) 37 logger.error('Error in Redis client.', { err })
@@ -45,7 +45,7 @@ class Redis {
45 this.prefix = 'redis-' + WEBSERVER.HOST + '-' 45 this.prefix = 'redis-' + WEBSERVER.HOST + '-'
46 } 46 }
47 47
48 static getRedisClient () { 48 static getRedisClientOptions () {
49 return Object.assign({}, 49 return Object.assign({},
50 (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {}, 50 (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {},
51 (CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {}, 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 /************* Forgot password *************/ 66 /************* Forgot password *************/
59 67
60 async setResetPasswordVerificationString (userId: number) { 68 async setResetPasswordVerificationString (userId: number) {
diff --git a/server/middlewares/cache.ts b/server/middlewares/cache.ts
index 091c82d92..ef8611875 100644
--- a/server/middlewares/cache.ts
+++ b/server/middlewares/cache.ts
@@ -1,73 +1,16 @@
1import * as express from 'express'
2import * as AsyncLock from 'async-lock'
3import { parseDurationToMs } from '../helpers/core-utils'
4import { Redis } from '../lib/redis' 1import { Redis } from '../lib/redis'
5import { logger } from '../helpers/logger' 2import * as apicache from 'apicache'
6 3
7const lock = new AsyncLock({ timeout: 5000 }) 4// Ensure Redis is initialized
5Redis.Instance.init()
8 6
9function cacheRoute (lifetimeArg: string | number) { 7const options = {
10 const lifetime = parseDurationToMs(lifetimeArg) 8 redisClient: Redis.Instance.getClient(),
11 9 appendKey: () => Redis.Instance.getPrefix()
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 }
69} 10}
70 11
12const cacheRoute = apicache.options(options).middleware
13
71// --------------------------------------------------------------------------- 14// ---------------------------------------------------------------------------
72 15
73export { 16export {
diff --git a/yarn.lock b/yarn.lock
index aa616f4a0..f2cc0ee05 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -16,6 +16,13 @@
16 dependencies: 16 dependencies:
17 any-observable "^0.3.0" 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"@types/async-lock@^1.1.0": 26"@types/async-lock@^1.1.0":
20 version "1.1.1" 27 version "1.1.1"
21 resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.1.tgz#81f218213bebcc5f740efe9648272c774a2e4b4b" 28 resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.1.tgz#81f218213bebcc5f740efe9648272c774a2e4b4b"
@@ -276,7 +283,7 @@
276 resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" 283 resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
277 integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== 284 integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
278 285
279"@types/redis@^2.8.5": 286"@types/redis@*", "@types/redis@^2.8.5":
280 version "2.8.12" 287 version "2.8.12"
281 resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.12.tgz#6405d7ece0d6cc037151b7141cef9ad3cd06f3ac" 288 resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.12.tgz#6405d7ece0d6cc037151b7141cef9ad3cd06f3ac"
282 integrity sha512-eT5cGYr08OnF6OlAHdc2hVOBAKBpfQQNQHsWEvUwRPFiXRd+vv+hOHSSIo4xB7M5vZOZdjMT2OUlXYqo3YlIGQ== 289 integrity sha512-eT5cGYr08OnF6OlAHdc2hVOBAKBpfQQNQHsWEvUwRPFiXRd+vv+hOHSSIo4xB7M5vZOZdjMT2OUlXYqo3YlIGQ==
@@ -548,6 +555,11 @@ anymatch@^2.0.0:
548 micromatch "^3.1.4" 555 micromatch "^3.1.4"
549 normalize-path "^2.1.1" 556 normalize-path "^2.1.1"
550 557
558apicache@^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
551append-field@^1.0.0: 563append-field@^1.0.0:
552 version "1.0.0" 564 version "1.0.0"
553 resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" 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 resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" 707 resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
696 integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== 708 integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
697 709
698async-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
703async-lru@^1.1.1: 710async-lru@^1.1.1:
704 version "1.1.2" 711 version "1.1.2"
705 resolved "https://registry.yarnpkg.com/async-lru/-/async-lru-1.1.2.tgz#abe831f3a52123c87d44273615e203b1ef04692e" 712 resolved "https://registry.yarnpkg.com/async-lru/-/async-lru-1.1.2.tgz#abe831f3a52123c87d44273615e203b1ef04692e"