chore: store the promise instead to combat race conditions

Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2022-10-03 15:15:23 +02:00
parent c31f7cdfbc
commit dcedf1bab5
2 changed files with 49 additions and 35 deletions
@@ -345,9 +345,10 @@ describe('DatabaseManager', () => {
});
it('returns the same client for the same pluginId', async () => {
const client1 = await manager.forPlugin('plugin1').getClient();
const client2 = await manager.forPlugin('plugin1').getClient();
const [client1, client2] = await Promise.all([
manager.forPlugin('plugin1').getClient(),
manager.forPlugin('plugin1').getClient(),
]);
expect(mocked(createDatabaseClient)).toHaveBeenCalledTimes(1);
expect(client1).toBe(client2);
@@ -84,7 +84,7 @@ export class DatabaseManager {
private readonly config: Config,
private readonly prefix: string = 'backstage_plugin_',
private readonly options?: DatabaseManagerOptions,
private readonly databaseCache: Map<string, Knex> = new Map(),
private readonly databaseCache: Map<string, Promise<Knex>> = new Map(),
) {}
/**
@@ -311,45 +311,58 @@ export class DatabaseManager {
if (this.databaseCache.has(pluginId)) {
return this.databaseCache.get(pluginId)!;
}
const pluginConfig = new ConfigReader(
this.getConfigForPlugin(pluginId) as JsonObject,
);
const databaseName = this.getDatabaseName(pluginId);
if (databaseName && this.getEnsureExistsConfig(pluginId)) {
const clientPromise = new Promise<Knex>(async (resolve, reject) => {
try {
await ensureDatabaseExists(pluginConfig, databaseName);
} catch (error) {
throw new Error(
`Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`,
const pluginConfig = new ConfigReader(
this.getConfigForPlugin(pluginId) as JsonObject,
);
}
}
let schemaOverrides;
if (this.getPluginDivisionModeConfig() === 'schema') {
schemaOverrides = this.getSchemaOverrides(pluginId);
if (this.getEnsureExistsConfig(pluginId)) {
try {
await ensureSchemaExists(pluginConfig, pluginId);
} catch (error) {
throw new Error(
`Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`,
);
const databaseName = this.getDatabaseName(pluginId);
if (databaseName && this.getEnsureExistsConfig(pluginId)) {
try {
await ensureDatabaseExists(pluginConfig, databaseName);
} catch (error) {
throw new Error(
`Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`,
);
}
}
let schemaOverrides;
if (this.getPluginDivisionModeConfig() === 'schema') {
schemaOverrides = this.getSchemaOverrides(pluginId);
if (this.getEnsureExistsConfig(pluginId)) {
try {
await ensureSchemaExists(pluginConfig, pluginId);
} catch (error) {
throw new Error(
`Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`,
);
}
}
}
const databaseClientOverrides = mergeDatabaseConfig(
{},
this.getDatabaseOverrides(pluginId),
schemaOverrides,
);
const client = createDatabaseClient(
pluginConfig,
databaseClientOverrides,
);
this.startKeepaliveLoop(pluginId, client);
resolve(client);
} catch (e) {
reject(e);
}
}
});
const databaseClientOverrides = mergeDatabaseConfig(
{},
this.getDatabaseOverrides(pluginId),
schemaOverrides,
);
this.databaseCache.set(pluginId, clientPromise);
const client = createDatabaseClient(pluginConfig, databaseClientOverrides);
this.startKeepaliveLoop(pluginId, client);
this.databaseCache.set(pluginId, client);
return client;
return clientPromise;
}
private startKeepaliveLoop(pluginId: string, client: Knex): void {