Limit concurrent local TechDocs builds.

Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
Eric Peterson
2022-06-02 16:25:27 +02:00
parent 6888c50c47
commit 61fba6e50b
3 changed files with 42 additions and 1 deletions
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs-backend': patch
---
In order to ensure a good, stable TechDocs user experience when running TechDocs with `techdocs.builder` set to `local`, the number of concurrent builds has been limited to 10. Any additional builds requested concurrently will be queued and handled as prior builds complete. In the unlikely event that you need to handle more concurrent builds, consider scaling out your TechDocs backend deployment or using the `external` option for `techdocs.builder`.
@@ -159,6 +159,37 @@ describe('DocsSynchronizer', () => {
expect(DocsBuilder.prototype.build).toBeCalledTimes(1);
});
it('should limit concurrent updates', async () => {
// Given a build implementation that runs long...
MockedDocsBuilder.prototype.build.mockImplementation(
() => new Promise(() => {}),
);
(shouldCheckForUpdate as jest.Mock).mockReturnValue(true);
const entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
uid: '0',
name: 'test',
namespace: 'default',
},
};
// When more than 10 syncs are attempted...
for (let i = 0; i < 12; i++) {
docsSynchronizer.doSync({
responseHandler: mockResponseHandler,
entity,
preparers,
generators,
});
}
// Then still only 10 builds should have been triggered.
await new Promise<void>(resolve => resolve());
expect(DocsBuilder.prototype.build).toHaveBeenCalledTimes(10);
});
it('should not check for an update too often', async () => {
(shouldCheckForUpdate as jest.Mock).mockReturnValue(false);
@@ -25,6 +25,7 @@ import {
PublisherBase,
} from '@backstage/plugin-techdocs-node';
import fetch from 'node-fetch';
import pLimit, { Limit } from 'p-limit';
import { PassThrough } from 'stream';
import * as winston from 'winston';
import { TechDocsCache } from '../cache';
@@ -47,6 +48,7 @@ export class DocsSynchronizer {
private readonly config: Config;
private readonly scmIntegrations: ScmIntegrationRegistry;
private readonly cache: TechDocsCache | undefined;
private readonly buildLimiter: Limit;
constructor({
publisher,
@@ -69,6 +71,9 @@ export class DocsSynchronizer {
this.publisher = publisher;
this.scmIntegrations = scmIntegrations;
this.cache = cache;
// Single host/process: limit concurrent builds up to 10 at a time.
this.buildLimiter = pLimit(10);
}
async doSync({
@@ -123,7 +128,7 @@ export class DocsSynchronizer {
cache: this.cache,
});
const updated = await docsBuilder.build();
const updated = await this.buildLimiter(() => docsBuilder.build());
if (!updated) {
finish({ updated: false });