diff options
author | Chocobozzz <me@florianbigard.com> | 2018-05-23 10:03:26 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-05-23 10:03:26 +0200 |
commit | b40f057594d51ae64e9d638d3b5877e544214b53 (patch) | |
tree | bd7918e8b5ab4f688422125a925cca9b6ff527bc /server/middlewares/cache.ts | |
parent | e1a540b5fa14b0fafa63f99e344927b10fdbee00 (diff) | |
download | PeerTube-b40f057594d51ae64e9d638d3b5877e544214b53.tar.gz PeerTube-b40f057594d51ae64e9d638d3b5877e544214b53.tar.zst PeerTube-b40f057594d51ae64e9d638d3b5877e544214b53.zip |
Handle concurrent requests in cache middleware
Diffstat (limited to 'server/middlewares/cache.ts')
-rw-r--r-- | server/middlewares/cache.ts | 53 |
1 files changed, 33 insertions, 20 deletions
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 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import * as AsyncLock from 'async-lock' | ||
2 | import { Redis } from '../lib/redis' | 3 | import { Redis } from '../lib/redis' |
3 | import { logger } from '../helpers/logger' | 4 | import { logger } from '../helpers/logger' |
4 | 5 | ||
6 | const lock = new AsyncLock({ timeout: 5000 }) | ||
7 | |||
5 | function cacheRoute (lifetime: number) { | 8 | function 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 | ||