WIP store-agnostic cache manager.

Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
Eric Peterson
2021-05-01 21:23:50 +02:00
parent d2eed74d35
commit 93ff8275dd
8 changed files with 202 additions and 9 deletions
+22
View File
@@ -68,6 +68,28 @@ export interface Config {
connection: string | object;
};
/** Cache connection configuration, select cache type using the `store` field */
cache?:
| {
store: 'memory';
}
| {
store: 'memcache';
connection: {
/**
* An array of memcache hosts, optionally including a port number.
* e.g. 127.0.0.1:11211
*/
hosts: string[];
/**
* Number of milliseconds to wait before assuming there is a
* network timeout. Defaults to 500ms.
*/
netTimeout?: number;
};
};
cors?: {
origin?: string | string[];
methods?: string | string[];
+4
View File
@@ -36,10 +36,13 @@
"@backstage/integration": "^0.5.2",
"@google-cloud/storage": "^5.8.0",
"@octokit/rest": "^18.5.3",
"@types/cache-manager": "^3.4.0",
"@types/cors": "^2.8.6",
"@types/dockerode": "^3.2.1",
"@types/express": "^4.17.6",
"archiver": "^5.0.2",
"cache-manager": "^3.4.3",
"cache-manager-memcached-store": "^4.0.0",
"compression": "^1.7.4",
"concat-stream": "^2.0.0",
"cors": "^2.8.5",
@@ -54,6 +57,7 @@
"knex": "^0.95.1",
"lodash": "^4.17.15",
"logform": "^2.1.1",
"memcache-pp": "^0.3.3",
"minimatch": "^3.0.4",
"minimist": "^1.2.5",
"morgan": "^1.10.0",
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Config } from '@backstage/config';
import cacheManager from 'cache-manager';
// @ts-expect-error
import Memcache from 'memcache-pp';
// @ts-expect-error
import memcachedStore from 'cache-manager-memcached-store';
/**
* A Cache Manager, which is able to retrieve a `node-cache-manager`-compliant
* cache client, configured according to app configuration. If no cache is
* configured, or an unknown store is provided, a no-op cache instance will be
* returned.
*/
export class CacheManager {
private readonly storeGetterMap = {
memcache: this.getMemcacheClient,
memory: this.getMemoryClient,
none: this.getNoneClient,
};
/**
* Creates a new CacheManager instance by reading from the `backend` config
* section, specifically the `.cache` key.
*
* @param config The loaded application configuration.
*/
static fromConfig(config: Config): CacheManager {
return new CacheManager(config.getConfig('backend.cache'));
}
private constructor(private readonly config: Config) {}
getClientWithTtl(ttl: number): cacheManager.Cache {
const store = this.config.getOptionalString(
'store',
) as keyof CacheManager['storeGetterMap'];
if (this.storeGetterMap.hasOwnProperty(store)) {
return this.storeGetterMap[store].call(this, ttl);
}
return this.storeGetterMap.none.call(this, ttl);
}
private getMemcacheClient(ttl: number): cacheManager.Cache {
const hosts = this.config.getStringArray('connection.hosts');
const netTimeout = this.config.getOptionalNumber('connection.netTimeout');
return cacheManager.caching({
store: memcachedStore,
driver: Memcache,
options: {
hosts,
...(netTimeout && { netTimeout }),
},
ttl,
});
}
private getMemoryClient(ttl: number): cacheManager.Cache {
return cacheManager.caching({
store: 'memory',
ttl,
});
}
private getNoneClient(ttl: number): cacheManager.Cache {
return cacheManager.caching({
store: 'none',
ttl,
});
}
}
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2021 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './CacheManager';
+1
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
export * from './cache';
export * from './config';
export * from './database';
export * from './discovery';
+3 -1
View File
@@ -24,6 +24,7 @@
import Router from 'express-promise-router';
import {
CacheManager,
createServiceBuilder,
getRootLogger,
loadBackendConfig,
@@ -59,11 +60,12 @@ function makeCreateEnv(config: Config) {
root.info(`Created UrlReader ${reader}`);
const databaseManager = SingleConnectionDatabaseManager.fromConfig(config);
const cache = CacheManager.fromConfig(config);
return (plugin: string): PluginEnvironment => {
const logger = root.child({ type: 'plugin', plugin });
const database = databaseManager.forPlugin(plugin);
return { logger, database, config, reader, discovery };
return { logger, cache, database, config, reader, discovery };
};
}
+2
View File
@@ -17,6 +17,7 @@
import { Logger } from 'winston';
import { Config } from '@backstage/config';
import {
CacheManager,
PluginDatabaseManager,
PluginEndpointDiscovery,
UrlReader,
@@ -24,6 +25,7 @@ import {
export type PluginEnvironment = {
logger: Logger;
cache: CacheManager;
database: PluginDatabaseManager;
config: Config;
reader: UrlReader;
+66 -8
View File
@@ -5737,6 +5737,11 @@
resolved "https://registry.npmjs.org/@types/btoa-lite/-/btoa-lite-1.0.0.tgz#e190a5a548e0b348adb0df9ac7fa5f1151c7cca4"
integrity sha512-wJsiX1tosQ+J5+bY5LrSahHxr2wT+uME5UDwdN1kg4frt40euqA+wzECkmq4t5QbveHiJepfdThgQrPw6KiSlg==
"@types/cache-manager@^3.4.0":
version "3.4.0"
resolved "https://registry.npmjs.org/@types/cache-manager/-/cache-manager-3.4.0.tgz#414136ea3807a8cd071b8f20370c5df5dbffd382"
integrity sha512-XVbn2HS+O+Mk2SKRCjr01/8oD5p2Tv1fxxdBqJ0+Cl+UBNiz0WVY5rusHpMGx+qF6Vc2pnRwPVwSKbGaDApCpw==
"@types/cacheable-request@^6.0.1":
version "6.0.1"
resolved "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976"
@@ -8152,6 +8157,11 @@ async@0.9.x:
resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
async@3.2.0, async@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
async@^2.0.1, async@^2.6.1, async@^2.6.2:
version "2.6.3"
resolved "https://registry.npmjs.org/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
@@ -8826,7 +8836,7 @@ block-stream@*:
dependencies:
inherits "~2.0.0"
bluebird@3.7.2, bluebird@^3.3.5, bluebird@^3.5.1, bluebird@^3.5.5, bluebird@^3.7.2:
bluebird@3.7.2, bluebird@^3.3.5, bluebird@^3.4.1, bluebird@^3.5.1, bluebird@^3.5.5, bluebird@^3.7.2:
version "3.7.2"
resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
@@ -9251,6 +9261,20 @@ cache-base@^1.0.1:
union-value "^1.0.0"
unset-value "^1.0.0"
cache-manager-memcached-store@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/cache-manager-memcached-store/-/cache-manager-memcached-store-4.0.0.tgz#f68d00cdfaa73696d13137b7b0f39397167d9220"
integrity sha512-Lv1WMaRC1FQHHqxE8Xbi7YWInhgfxjOmLEE6u1K0A3Rwmq+XRLyekKDM7aW9WIzF+PuII/RDKqBK/Ezo5H2QVw==
cache-manager@^3.4.3:
version "3.4.3"
resolved "https://registry.npmjs.org/cache-manager/-/cache-manager-3.4.3.tgz#c978d58f82b414ade08903d4d72b56a80a4978be"
integrity sha512-6+Hfzy1SNs/thUwo+07pV0ozgxc4sadrAN0eFVGvXl/X9nz3J0BqEnnEoyxEn8jnF+UkEo0MKpyk9BO80hMeiQ==
dependencies:
async "3.2.0"
lodash "^4.17.21"
lru-cache "6.0.0"
cacheable-lookup@^5.0.3:
version "5.0.3"
resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz#049fdc59dffdd4fc285e8f4f82936591bd59fec3"
@@ -9457,6 +9481,11 @@ capture-exit@^2.0.0:
dependencies:
rsvp "^4.8.4"
carrier@^0.3.0:
version "0.3.0"
resolved "https://registry.npmjs.org/carrier/-/carrier-0.3.0.tgz#bd295d1d3a7524cac63dd779b929ee22a362bad4"
integrity sha1-vSldHTp1JMrGPdd5uSnuIqNiutQ=
case-sensitive-paths-webpack-plugin@^2.2.0:
version "2.3.0"
resolved "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz#23ac613cc9a856e4f88ff8bb73bbb5e989825cf7"
@@ -10273,6 +10302,11 @@ connect-history-api-fallback@^1.6.0:
resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
connection-parse@0.0.x:
version "0.0.7"
resolved "https://registry.npmjs.org/connection-parse/-/connection-parse-0.0.7.tgz#18e7318aab06a699267372b10c5226d25a1c9a69"
integrity sha1-GOcxiqsGppkmc3KxDFIm0locmmk=
console-browserify@^1.1.0:
version "1.2.0"
resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
@@ -14746,6 +14780,14 @@ hash.js@^1.0.0, hash.js@^1.0.3:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
hashring@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/hashring/-/hashring-3.2.0.tgz#fda4efde8aa22cdb97fb1d2a65e88401e1c144ce"
integrity sha1-/aTv3oqiLNuX+x0qZeiEAeHBRM4=
dependencies:
connection-parse "0.0.x"
simple-lru-cache "0.0.x"
hast-util-parse-selector@^2.0.0:
version "2.2.4"
resolved "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.4.tgz#60c99d0b519e12ab4ed32e58f150ec3f61ed1974"
@@ -18023,6 +18065,13 @@ lru-cache@2:
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=
lru-cache@6.0.0, lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
lru-cache@^4.0.1:
version "4.1.5"
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
@@ -18038,13 +18087,6 @@ lru-cache@^5.0.0, lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
lru-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3"
@@ -18336,6 +18378,17 @@ media-typer@0.3.0:
resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
memcache-pp@^0.3.3:
version "0.3.3"
resolved "https://registry.npmjs.org/memcache-pp/-/memcache-pp-0.3.3.tgz#3124830e27d55a252499726510841590ac130c99"
integrity sha512-fMitetT5ulUs4DnFaoVqWHrTBiddLG/l8rMHXbV+ibuL7uWjBulaEf8koTBEweyrjmflqhbH4Uy9V709LadXSA==
dependencies:
bluebird "^3.4.1"
carrier "^0.3.0"
debug "^2.6.9"
hashring "^3.2.0"
immutable "^3.8.1"
memoize-one@^5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
@@ -23780,6 +23833,11 @@ simple-get@^3.0.2, simple-get@^3.0.3:
once "^1.3.1"
simple-concat "^1.0.0"
simple-lru-cache@0.0.x:
version "0.0.2"
resolved "https://registry.npmjs.org/simple-lru-cache/-/simple-lru-cache-0.0.2.tgz#d59cc3a193c1a5d0320f84ee732f6e4713e511dd"
integrity sha1-1ZzDoZPBpdAyD4Tucy9uRxPlEd0=
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"