Initial implementation of TechDocs cache in backend plugin

Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
Eric Peterson
2021-07-24 17:00:22 +02:00
committed by Eric Peterson
parent 3e443e8e31
commit 0a44eb7d52
3 changed files with 47 additions and 2 deletions
+17
View File
@@ -226,6 +226,23 @@ export interface Config {
};
};
/**
* @example http://localhost:7007/api/techdocs
* Techdocs cache information
*/
cache?: {
/**
* The cache time-to-live for TechDocs sites (in milliseconds). Set this
* to a non-zero value to cache TechDocs sites and assets as they are
* read from storage.
*
* Note: you must also configure `backend.cache` appropriately as well,
* and to pass a PluginCacheManager instance to TechDocs Backend's
* createRouter method in your backend.
*/
ttl: number;
};
/**
* @example http://localhost:7007/api/techdocs
* @visibility frontend
@@ -36,6 +36,7 @@ import path from 'path';
import { Writable } from 'stream';
import { Logger } from 'winston';
import { BuildMetadataStorage } from './BuildMetadataStorage';
import { TechDocsCache } from '../cache';
type DocsBuilderArguments = {
preparers: PreparerBuilder;
@@ -46,6 +47,7 @@ type DocsBuilderArguments = {
config: Config;
scmIntegrations: ScmIntegrationRegistry;
logStream?: Writable;
cache?: TechDocsCache;
};
export class DocsBuilder {
@@ -57,6 +59,7 @@ export class DocsBuilder {
private config: Config;
private scmIntegrations: ScmIntegrationRegistry;
private logStream: Writable | undefined;
private cache?: TechDocsCache;
constructor({
preparers,
@@ -67,6 +70,7 @@ export class DocsBuilder {
config,
scmIntegrations,
logStream,
cache,
}: DocsBuilderArguments) {
this.preparer = preparers.get(entity);
this.generator = generators.get(entity);
@@ -76,6 +80,7 @@ export class DocsBuilder {
this.config = config;
this.scmIntegrations = scmIntegrations;
this.logStream = logStream;
this.cache = cache;
}
/**
@@ -210,11 +215,16 @@ export class DocsBuilder {
)}`,
);
await this.publisher.publish({
const published = await this.publisher.publish({
entity: this.entity,
directory: outputDir,
});
// Invalidate the cache for any published objects.
if (this.cache && published?.objects?.length) {
await this.cache.invalidateMultiple(published.objects);
}
try {
// Not a blocker hence no need to await this.
fs.remove(outputDir);
+19 -1
View File
@@ -13,7 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import {
PluginEndpointDiscovery,
PluginCacheManager,
} from '@backstage/backend-common';
import { CatalogClient } from '@backstage/catalog-client';
import { Entity, stringifyEntityRef } from '@backstage/catalog-model';
import { Config } from '@backstage/config';
@@ -31,6 +34,7 @@ import { Knex } from 'knex';
import { Logger } from 'winston';
import { ScmIntegrations } from '@backstage/integration';
import { DocsSynchronizer, DocsSynchronizerSyncOpts } from './DocsSynchronizer';
import { createCacheMiddleware, TechDocsCache } from '../cache';
/**
* All of the required dependencies for running TechDocs in the "out-of-the-box"
@@ -44,6 +48,7 @@ type OutOfTheBoxDeploymentOptions = {
discovery: PluginEndpointDiscovery;
database?: Knex; // TODO: Make database required when we're implementing database stuff.
config: Config;
cache?: PluginCacheManager;
};
/**
@@ -88,6 +93,14 @@ export async function createRouter(
scmIntegrations,
});
// Set up a cache client if configured.
let cache: TechDocsCache | undefined;
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 });
}
router.get('/metadata/techdocs/:namespace/:kind/:name', async (req, res) => {
const { kind, namespace, name } = req.params;
const entityName = { kind, namespace, name };
@@ -199,6 +212,11 @@ export async function createRouter(
);
});
// If a cache manager was provided, attach the cache middleware.
if (cache) {
router.use(createCacheMiddleware({ logger, cache }));
}
// Route middleware which serves files from the storage set in the publisher.
router.use('/static/docs', publisher.docsRouter());