Make cache readTimeout configurable.
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
committed by
Eric Peterson
parent
da0867f952
commit
ef04b09f75
+25
-2
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { CacheClient, getVoidLogger } from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { CacheInvalidationError, TechDocsCache } from './TechDocsCache';
|
||||
|
||||
const cached = (str: string): string => {
|
||||
@@ -31,7 +32,7 @@ describe('TechDocsCache', () => {
|
||||
set: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
};
|
||||
CacheUnderTest = new TechDocsCache({
|
||||
CacheUnderTest = TechDocsCache.fromConfig(new ConfigReader({}), {
|
||||
cache: MockClient,
|
||||
logger: getVoidLogger(),
|
||||
});
|
||||
@@ -55,7 +56,7 @@ describe('TechDocsCache', () => {
|
||||
expect(actual).toBe(undefined);
|
||||
});
|
||||
|
||||
it('returns undefined if no response after 1s', async () => {
|
||||
it('returns undefined if no response after 1s by default', async () => {
|
||||
const expectedPath = 'some/index.html';
|
||||
MockClient.get.mockImplementationOnce(() => {
|
||||
return new Promise(resolve => {
|
||||
@@ -66,6 +67,28 @@ describe('TechDocsCache', () => {
|
||||
expect(actual).toBe(undefined);
|
||||
});
|
||||
|
||||
it('returns undefined if no response after configured readTimeout', async () => {
|
||||
const expectedPath = 'some/index.html';
|
||||
MockClient.get.mockImplementationOnce(() => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => resolve(cached('value')), 20);
|
||||
});
|
||||
});
|
||||
|
||||
CacheUnderTest = TechDocsCache.fromConfig(
|
||||
new ConfigReader({
|
||||
techdocs: { cache: { readTimeout: 10 } },
|
||||
}),
|
||||
{
|
||||
cache: MockClient,
|
||||
logger: getVoidLogger(),
|
||||
},
|
||||
);
|
||||
|
||||
const actual = await CacheUnderTest.get(expectedPath);
|
||||
expect(actual).toBe(undefined);
|
||||
});
|
||||
|
||||
it('returns data if cache get returns it', async () => {
|
||||
const expectedPath = 'some/index.html';
|
||||
MockClient.get.mockResolvedValueOnce(cached('expected value'));
|
||||
|
||||
+24
-2
@@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { CacheClient } from '@backstage/backend-common';
|
||||
import { assertError } from '@backstage/errors';
|
||||
import { Config } from '@backstage/config';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
export class CacheInvalidationError extends Error {
|
||||
@@ -28,10 +30,29 @@ export class CacheInvalidationError extends Error {
|
||||
export class TechDocsCache {
|
||||
protected readonly cache: CacheClient;
|
||||
protected readonly logger: Logger;
|
||||
protected readonly readTimeout: number;
|
||||
|
||||
constructor({ cache, logger }: { cache: CacheClient; logger: Logger }) {
|
||||
private constructor({
|
||||
cache,
|
||||
logger,
|
||||
readTimeout,
|
||||
}: {
|
||||
cache: CacheClient;
|
||||
logger: Logger;
|
||||
readTimeout: number;
|
||||
}) {
|
||||
this.cache = cache;
|
||||
this.logger = logger;
|
||||
this.readTimeout = readTimeout;
|
||||
}
|
||||
|
||||
static fromConfig(
|
||||
config: Config,
|
||||
{ cache, logger }: { cache: CacheClient; logger: Logger },
|
||||
) {
|
||||
const readTimeout =
|
||||
config.getOptionalNumber('techdocs.cache.readTimeout') || 1000;
|
||||
return new TechDocsCache({ cache, logger, readTimeout });
|
||||
}
|
||||
|
||||
async get(path: string): Promise<Buffer | undefined> {
|
||||
@@ -40,7 +61,7 @@ export class TechDocsCache {
|
||||
// temporarily unreachable.
|
||||
const response = (await Promise.race([
|
||||
this.cache.get(path),
|
||||
new Promise(cancelAfter => setTimeout(cancelAfter, 1000)),
|
||||
new Promise(cancelAfter => setTimeout(cancelAfter, this.readTimeout)),
|
||||
])) as string | undefined;
|
||||
|
||||
if (response !== undefined) {
|
||||
@@ -51,6 +72,7 @@ export class TechDocsCache {
|
||||
this.logger.debug(`Cache miss: ${path}`);
|
||||
return response;
|
||||
} catch (e) {
|
||||
assertError(e);
|
||||
this.logger.warn(`Error getting cache entry ${path}: ${e.message}`);
|
||||
this.logger.debug(e.stack);
|
||||
return undefined;
|
||||
|
||||
@@ -91,7 +91,7 @@ export async function createRouter(
|
||||
const defaultTtl = config.getOptionalNumber('techdocs.cache.ttl');
|
||||
if (isOutOfTheBoxOption(options) && options.cache && defaultTtl) {
|
||||
const cacheClient = options.cache.getClient({ defaultTtl });
|
||||
cache = new TechDocsCache({ cache: cacheClient, logger });
|
||||
cache = TechDocsCache.fromConfig(config, { cache: cacheClient, logger });
|
||||
}
|
||||
|
||||
const scmIntegrations = ScmIntegrations.fromConfig(config);
|
||||
|
||||
Reference in New Issue
Block a user