Add root lifecycle shutdown hook to clean up DB connections

Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
Eric Peterson
2024-10-01 12:57:15 +02:00
parent 8376e12039
commit b1254b40a8
2 changed files with 38 additions and 2 deletions
@@ -89,6 +89,27 @@ export class DatabaseManagerImpl {
return { getClient, migrations: { skip } };
}
/**
* Method to be called during shutdown to destroy all known connections.
*/
async shutdown(deps: { logger: LoggerService }): Promise<void> {
const pluginIds = Array.from(this.databaseCache.keys());
await Promise.all(
pluginIds.map(async pluginId => {
const connection = await this.databaseCache.get(pluginId);
if (connection) {
await connection.destroy().catch((error: unknown) => {
deps.logger.error(
`Problem closing database connection for ${pluginId}: ${stringifyError(
error,
)}`,
);
});
}
}),
);
}
/**
* Provides the client type which should be used for a given plugin.
*
@@ -236,4 +257,11 @@ export class DatabaseManager {
): PluginDatabaseManager {
return this.impl.forPlugin(pluginId, deps);
}
/**
* Method to be called during shutdown to destroy all known connections.
*/
async shutdown(deps: { logger: LoggerService }): Promise<void> {
return this.impl.shutdown(deps);
}
}
@@ -37,9 +37,11 @@ export const databaseServiceFactory = createServiceFactory({
lifecycle: coreServices.lifecycle,
logger: coreServices.logger,
pluginMetadata: coreServices.pluginMetadata,
rootLifecycle: coreServices.rootLifecycle,
rootLogger: coreServices.rootLogger,
},
async createRootContext({ config }) {
return config.getOptional('backend.database')
async createRootContext({ config, rootLifecycle, rootLogger }) {
const databaseManager = config.getOptional('backend.database')
? DatabaseManager.fromConfig(config)
: DatabaseManager.fromConfig(
new ConfigReader({
@@ -48,6 +50,12 @@ export const databaseServiceFactory = createServiceFactory({
},
}),
);
rootLifecycle.addShutdownHook(async () => {
await databaseManager.shutdown({ logger: rootLogger });
});
return databaseManager;
},
async factory({ pluginMetadata, lifecycle, logger }, databaseManager) {
return databaseManager.forPlugin(pluginMetadata.getId(), {