diff --git a/.gitignore b/.gitignore index 2ce9790..84e024f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /node_modules/ /public/_assets/ +/dump.rdb /stats.json npm-debug.log* diff --git a/modules/__tests__/utils/closeDatabase.js b/modules/__tests__/utils/closeDatabase.js index 5f029dc..6c78595 100644 --- a/modules/__tests__/utils/closeDatabase.js +++ b/modules/__tests__/utils/closeDatabase.js @@ -1,8 +1,6 @@ -const cache = require('../../utils/cache'); const data = require('../../utils/data'); function closeDatabase() { - cache.quit(); data.quit(); } diff --git a/modules/utils/cache.js b/modules/utils/cache.js index 98cf1b7..526c859 100644 --- a/modules/utils/cache.js +++ b/modules/utils/cache.js @@ -1,9 +1,23 @@ -const redis = require('redis'); +const LRUCache = require('lru-cache'); -redis.debug_mode = process.env.DEBUG_REDIS != null; +const maxMegabytes = 40; // Cap the cache at 40 MB +const maxLength = maxMegabytes * 1024 * 1024; -const client = redis.createClient( - process.env.CACHE_URL || process.env.OPENREDIS_URL || 'redis://localhost:6379' -); +const maxSeconds = 60; +const maxAge = maxSeconds * 1000; -module.exports = client; +const cache = new LRUCache({ + max: maxLength, + maxAge: maxAge, + length: Buffer.byteLength +}); + +function get(key) { + return cache.get(key); +} + +function setex(key, ttlSeconds, value) { + return cache.set(key, value, ttlSeconds * 1000); +} + +module.exports = { get, setex }; diff --git a/modules/utils/fetchNpmPackage.js b/modules/utils/fetchNpmPackage.js index 444f0a1..1f1fd32 100644 --- a/modules/utils/fetchNpmPackage.js +++ b/modules/utils/fetchNpmPackage.js @@ -9,7 +9,7 @@ const logging = require('./logging'); function fetchNpmPackage(packageConfig) { return new Promise((resolve, reject) => { - const tarballURL = packageConfig.dist.tarball; + const tarballURL = packageConfig.tarballURL; logging.debug( 'Fetching package for %s from %s', diff --git a/modules/utils/getNpmPackageInfo.js b/modules/utils/getNpmPackageInfo.js index 7b44de3..369b8cb 100644 --- a/modules/utils/getNpmPackageInfo.js +++ b/modules/utils/getNpmPackageInfo.js @@ -1,15 +1,18 @@ const cache = require('./cache'); const fetchNpmPackageInfo = require('./fetchNpmPackageInfo'); -const notFound = 0; +const notFound = ''; function cleanPackageConfig(packageConfig) { return { name: packageConfig.name, version: packageConfig.version, - dependencies: packageConfig.dependencies, - peerDependencies: packageConfig.peerDependencies, - dist: packageConfig.dist + dependencies: Object.assign( + {}, + packageConfig.dependencies, + packageConfig.peerDependencies + ), + tarballURL: packageConfig.dist.tarball }; } @@ -26,32 +29,31 @@ function cleanPackageInfo(packageInfo) { function getNpmPackageInfo(packageName) { return new Promise((resolve, reject) => { const key = `npmPackageInfo-${packageName}`; + const value = cache.get(key); - cache.get(key, (error, value) => { - if (error) { - reject(error); - } else if (value != null) { - resolve(value === notFound ? null : JSON.parse(value)); - } else { - fetchNpmPackageInfo(packageName).then(value => { - if (value == null) { - // Cache 404s for 5 minutes. This prevents us from making - // unnecessary requests to the registry for bad package names. - // In the worst case, a brand new package's info will be - // available within 5 minutes. - cache.setex(key, 300, notFound); - resolve(null); - } else { - const cachedValue = JSON.stringify(cleanPackageInfo(value)); + if (value != null) { + console.log('GOT VALUE'); + resolve(value === notFound ? null : JSON.parse(value)); + } else { + console.log('NO VALUE'); + fetchNpmPackageInfo(packageName).then(value => { + if (value == null) { + // Cache 404s for 5 minutes. This prevents us from making + // unnecessary requests to the registry for bad package names. + // In the worst case, a brand new package's info will be + // available within 5 minutes. + cache.setex(key, 300, notFound); + resolve(null); + } else { + value = cleanPackageInfo(value); - // Cache valid package info for 1 minute. In the worst case, - // new versions won't be available for 1 minute. - cache.setex(key, 60, cachedValue); - resolve(value); - } - }, reject); - } - }); + // Cache valid package info for 1 minute. In the worst case, + // new versions won't be available for 1 minute. + cache.setex(key, 60, JSON.stringify(value)); + resolve(value); + } + }, reject); + } }); } diff --git a/package-lock.json b/package-lock.json index b2b7776..f8107ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4254,11 +4254,27 @@ "y18n": "^4.0.0" }, "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true } } }, @@ -5036,6 +5052,24 @@ "lru-cache": "^4.0.1", "shebang-command": "^1.2.0", "which": "^1.2.9" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } } }, "crypt": { @@ -9989,12 +10023,10 @@ "dev": true }, "lru-cache": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.4.tgz", - "integrity": "sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==", - "dev": true, + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "requires": { - "pseudomap": "^1.0.2", "yallist": "^3.0.2" } }, @@ -16416,8 +16448,7 @@ "yallist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", - "dev": true + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" }, "yargs": { "version": "10.1.2", diff --git a/package.json b/package.json index 3061309..58afa32 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "invariant": "^2.2.2", "isomorphic-fetch": "^2.2.1", "jsonwebtoken": "^8.1.0", + "lru-cache": "^5.1.1", "mime": "^1.4.0", "morgan": "^1.8.1", "ndjson": "^1.5.0",