From 47f6409bb8bc49a50027b9579bb651c0506b6912 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 25 Apr 2019 11:27:13 +0200 Subject: [PATCH] Use apicache instead of our broken implementation --- package.json | 3 +- server/lib/job-queue/job-queue.ts | 2 +- server/lib/redis.ts | 12 ++++- server/middlewares/cache.ts | 73 ++++--------------------------- yarn.lock | 19 +++++--- 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 @@ "@types/bluebird": "3.5.21" }, "dependencies": { + "apicache": "^1.4.0", "application-config": "^1.0.1", "async": "^2.0.0", - "async-lock": "^1.1.2", "async-lru": "^1.1.1", "bcrypt": "3.0.5", "bittorrent-tracker": "^9.0.0", @@ -159,6 +159,7 @@ "youtube-dl": "^1.12.2" }, "devDependencies": { + "@types/apicache": "^1.2.0", "@types/async": "^2.0.40", "@types/async-lock": "^1.1.0", "@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 { this.jobRedisPrefix = 'bull-' + WEBSERVER.HOST const queueOptions = { prefix: this.jobRedisPrefix, - redis: Redis.getRedisClient(), + redis: Redis.getRedisClientOptions(), settings: { maxStalledCount: 10 // transcoding could be long, so jobs can often be interrupted by restarts } 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 { if (this.initialized === true) return this.initialized = true - this.client = createClient(Redis.getRedisClient()) + this.client = createClient(Redis.getRedisClientOptions()) this.client.on('error', err => { logger.error('Error in Redis client.', { err }) @@ -45,7 +45,7 @@ class Redis { this.prefix = 'redis-' + WEBSERVER.HOST + '-' } - static getRedisClient () { + static getRedisClientOptions () { return Object.assign({}, (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {}, (CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {}, @@ -55,6 +55,14 @@ class Redis { ) } + getClient () { + return this.client + } + + getPrefix () { + return this.prefix + } + /************* Forgot password *************/ 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 @@ -import * as express from 'express' -import * as AsyncLock from 'async-lock' -import { parseDurationToMs } from '../helpers/core-utils' import { Redis } from '../lib/redis' -import { logger } from '../helpers/logger' +import * as apicache from 'apicache' -const lock = new AsyncLock({ timeout: 5000 }) +// Ensure Redis is initialized +Redis.Instance.init() -function cacheRoute (lifetimeArg: string | number) { - const lifetime = parseDurationToMs(lifetimeArg) - - return async function (req: express.Request, res: express.Response, next: express.NextFunction) { - const redisKey = Redis.Instance.generateCachedRouteKey(req) - - try { - await lock.acquire(redisKey, async (done) => { - const cached = await Redis.Instance.getCachedRoute(req) - - // Not cached - if (!cached) { - logger.debug('No cached results for route %s.', req.originalUrl) - - const sendSave = res.send.bind(res) - const redirectSave = res.redirect.bind(res) - - res.send = (body) => { - if (res.statusCode >= 200 && res.statusCode < 400) { - const contentType = res.get('content-type') - - Redis.Instance.setCachedRoute(req, body, lifetime, contentType, res.statusCode) - .then(() => done()) - .catch(err => { - logger.error('Cannot cache route.', { err }) - return done(err) - }) - } else { - done() - } - - return sendSave(body) - } - - res.redirect = url => { - done() - - return redirectSave(url) - } - - return next() - } - - if (cached.contentType) res.set('content-type', cached.contentType) - - if (cached.statusCode) { - const statusCode = parseInt(cached.statusCode, 10) - if (!isNaN(statusCode)) res.status(statusCode) - } - - logger.debug('Use cached result for %s.', req.originalUrl) - res.send(cached.body).end() - - return done() - }) - } catch (err) { - logger.error('Cannot serve cached route.', { err }) - return next() - } - } +const options = { + redisClient: Redis.Instance.getClient(), + appendKey: () => Redis.Instance.getPrefix() } +const cacheRoute = apicache.options(options).middleware + // --------------------------------------------------------------------------- export { diff --git a/yarn.lock b/yarn.lock index aa616f4a0..f2cc0ee05 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,6 +16,13 @@ dependencies: any-observable "^0.3.0" +"@types/apicache@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/apicache/-/apicache-1.2.0.tgz#5f6e9225e66d22da97042a39ad626b3c158d650d" + integrity sha512-8uatdizj2GbYHtS4u+x4k2aG1thG6JBWKRidcnauXav+Bxe3bHsWS8HSwcybuLE2q39/95cwb4hkHvqmP7ja2w== + dependencies: + "@types/redis" "*" + "@types/async-lock@^1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.1.tgz#81f218213bebcc5f740efe9648272c774a2e4b4b" @@ -276,7 +283,7 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== -"@types/redis@^2.8.5": +"@types/redis@*", "@types/redis@^2.8.5": version "2.8.12" resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.12.tgz#6405d7ece0d6cc037151b7141cef9ad3cd06f3ac" integrity sha512-eT5cGYr08OnF6OlAHdc2hVOBAKBpfQQNQHsWEvUwRPFiXRd+vv+hOHSSIo4xB7M5vZOZdjMT2OUlXYqo3YlIGQ== @@ -548,6 +555,11 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" +apicache@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/apicache/-/apicache-1.4.0.tgz#3835fbe18717caca3a44cb6272d49b52cac30d3a" + integrity sha512-pX/Sf9q9HNzAC5F+hPgxt8v3eQVZkXL/+8HpAnrDJXFmma80F2aHAAeWTql3BsG87lc3T6A7CFPNWMTl97L/7Q== + append-field@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" @@ -695,11 +707,6 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== -async-lock@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.2.0.tgz#cd6a53cb1ec3f86af25eafdeb6bc7c6e317258b8" - integrity sha512-81HzTQm4+qMj6PwNlnR+y9g7pDdGGzd/YBUrQnHk+BhR28ja2qv497NkQQc1KcKEqh/RShm07di2b0cIWVFrNQ== - async-lru@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/async-lru/-/async-lru-1.1.2.tgz#abe831f3a52123c87d44273615e203b1ef04692e" -- 2.25.1