aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-05-23 10:03:26 +0200
committerChocobozzz <me@florianbigard.com>2018-05-23 10:03:26 +0200
commitb40f057594d51ae64e9d638d3b5877e544214b53 (patch)
treebd7918e8b5ab4f688422125a925cca9b6ff527bc /server
parente1a540b5fa14b0fafa63f99e344927b10fdbee00 (diff)
downloadPeerTube-b40f057594d51ae64e9d638d3b5877e544214b53.tar.gz
PeerTube-b40f057594d51ae64e9d638d3b5877e544214b53.tar.zst
PeerTube-b40f057594d51ae64e9d638d3b5877e544214b53.zip
Handle concurrent requests in cache middleware
Diffstat (limited to 'server')
-rw-r--r--server/lib/redis.ts24
-rw-r--r--server/middlewares/cache.ts53
2 files changed, 45 insertions, 32 deletions
diff --git a/server/lib/redis.ts b/server/lib/redis.ts
index 97ff3598b..5bd55109c 100644
--- a/server/lib/redis.ts
+++ b/server/lib/redis.ts
@@ -88,6 +88,18 @@ class Redis {
88 }) 88 })
89 } 89 }
90 90
91 generateResetPasswordKey (userId: number) {
92 return 'reset-password-' + userId
93 }
94
95 buildViewKey (ip: string, videoUUID: string) {
96 return videoUUID + '-' + ip
97 }
98
99 buildCachedRouteKey (req: express.Request) {
100 return req.method + '-' + req.originalUrl
101 }
102
91 private getValue (key: string) { 103 private getValue (key: string) {
92 return new Promise<string>((res, rej) => { 104 return new Promise<string>((res, rej) => {
93 this.client.get(this.prefix + key, (err, value) => { 105 this.client.get(this.prefix + key, (err, value) => {
@@ -146,18 +158,6 @@ class Redis {
146 }) 158 })
147 } 159 }
148 160
149 private generateResetPasswordKey (userId: number) {
150 return 'reset-password-' + userId
151 }
152
153 private buildViewKey (ip: string, videoUUID: string) {
154 return videoUUID + '-' + ip
155 }
156
157 private buildCachedRouteKey (req: express.Request) {
158 return req.method + '-' + req.originalUrl
159 }
160
161 static get Instance () { 161 static get Instance () {
162 return this.instance || (this.instance = new this()) 162 return this.instance || (this.instance = new this())
163 } 163 }
diff --git a/server/middlewares/cache.ts b/server/middlewares/cache.ts
index c589ef683..bf6659687 100644
--- a/server/middlewares/cache.ts
+++ b/server/middlewares/cache.ts
@@ -1,39 +1,52 @@
1import * as express from 'express' 1import * as express from 'express'
2import * as AsyncLock from 'async-lock'
2import { Redis } from '../lib/redis' 3import { Redis } from '../lib/redis'
3import { logger } from '../helpers/logger' 4import { logger } from '../helpers/logger'
4 5
6const lock = new AsyncLock({ timeout: 5000 })
7
5function cacheRoute (lifetime: number) { 8function cacheRoute (lifetime: number) {
6 return async function (req: express.Request, res: express.Response, next: express.NextFunction) { 9 return async function (req: express.Request, res: express.Response, next: express.NextFunction) {
7 const cached = await Redis.Instance.getCachedRoute(req) 10 const redisKey = Redis.Instance.buildCachedRouteKey(req)
11
12 await lock.acquire(redisKey, async (done) => {
13 const cached = await Redis.Instance.getCachedRoute(req)
8 14
9 // Not cached 15 // Not cached
10 if (!cached) { 16 if (!cached) {
11 logger.debug('Not cached result for route %s.', req.originalUrl) 17 logger.debug('Not cached result for route %s.', req.originalUrl)
12 18
13 const sendSave = res.send.bind(res) 19 const sendSave = res.send.bind(res)
14 20
15 res.send = (body) => { 21 res.send = (body) => {
16 if (res.statusCode >= 200 && res.statusCode < 400) { 22 if (res.statusCode >= 200 && res.statusCode < 400) {
17 const contentType = res.getHeader('content-type').toString() 23 const contentType = res.getHeader('content-type').toString()
18 Redis.Instance.setCachedRoute(req, body, lifetime, contentType, res.statusCode) 24 Redis.Instance.setCachedRoute(req, body, lifetime, contentType, res.statusCode)
19 .catch(err => logger.error('Cannot cache route.', { err })) 25 .then(() => done())
26 .catch(err => {
27 logger.error('Cannot cache route.', { err })
28 return done(err)
29 })
30 }
31
32 return sendSave(body)
20 } 33 }
21 34
22 return sendSave(body) 35 return next()
23 } 36 }
24 37
25 return next() 38 if (cached.contentType) res.contentType(cached.contentType)
26 }
27 39
28 if (cached.contentType) res.contentType(cached.contentType) 40 if (cached.statusCode) {
41 const statusCode = parseInt(cached.statusCode, 10)
42 if (!isNaN(statusCode)) res.status(statusCode)
43 }
29 44
30 if (cached.statusCode) { 45 logger.debug('Use cached result for %s.', req.originalUrl)
31 const statusCode = parseInt(cached.statusCode, 10) 46 res.send(cached.body).end()
32 if (!isNaN(statusCode)) res.status(statusCode)
33 }
34 47
35 logger.debug('Use cached result for %s.', req.originalUrl) 48 return done()
36 return res.send(cached.body).end() 49 })
37 } 50 }
38} 51}
39 52