From 735747c939ed50a996ffc08a646a336e69983c17 Mon Sep 17 00:00:00 2001 From: Jonathan Jogenfors Date: Thu, 29 Feb 2024 22:50:06 +0100 Subject: [PATCH] add library teardown --- server/e2e/jobs/specs/library-watcher.e2e-spec.ts | 2 +- server/src/domain/library/library.service.spec.ts | 2 +- server/src/domain/library/library.service.ts | 12 ++++++++++-- .../src/domain/repositories/database.repository.ts | 1 + server/src/infra/repositories/database.repository.ts | 9 +++++++-- server/src/microservices/app.service.ts | 3 +-- server/src/test-utils/utils.ts | 6 +++--- server/test/repositories/database.repository.mock.ts | 1 + 8 files changed, 25 insertions(+), 11 deletions(-) diff --git a/server/e2e/jobs/specs/library-watcher.e2e-spec.ts b/server/e2e/jobs/specs/library-watcher.e2e-spec.ts index 93f7163531..1dc68ad12c 100644 --- a/server/e2e/jobs/specs/library-watcher.e2e-spec.ts +++ b/server/e2e/jobs/specs/library-watcher.e2e-spec.ts @@ -33,7 +33,7 @@ describe(`Library watcher (e2e)`, () => { }); afterEach(async () => { - await libraryService.unwatchAll(); + await libraryService.teardown(); }); afterAll(async () => { diff --git a/server/src/domain/library/library.service.spec.ts b/server/src/domain/library/library.service.spec.ts index 7a322c3c06..50b26d158b 100644 --- a/server/src/domain/library/library.service.spec.ts +++ b/server/src/domain/library/library.service.spec.ts @@ -1312,7 +1312,7 @@ describe(LibraryService.name, () => { storageMock.watch.mockImplementation(makeMockWatcher({ close: mockClose })); await sut.init(); - await sut.unwatchAll(); + await sut.tearDown(); expect(mockClose).toHaveBeenCalledTimes(2); }); diff --git a/server/src/domain/library/library.service.ts b/server/src/domain/library/library.service.ts index 5fce250f35..a9c34195ce 100644 --- a/server/src/domain/library/library.service.ts +++ b/server/src/domain/library/library.service.ts @@ -78,8 +78,8 @@ export class LibraryService extends EventEmitter { if (watch.enabled) { // This ensures that library watching only occurs in one microservice // TODO: we could make the lock be per-library instead of global - this.watchLock = await this.databaseRepository.tryLock(DatabaseLock.LibraryWatch); + this.watchLibraries = this.watchLock; } this.jobRepository.addCronJob( @@ -179,7 +179,15 @@ export class LibraryService extends EventEmitter { } } - async unwatchAll() { + async teardown() { + await this.unwatchAll(); + + if (this.watchLock) { + await this.databaseRepository.releaseLock(DatabaseLock.LibraryWatch); + } + } + + private async unwatchAll() { for (const id in this.watchers) { await this.unwatch(id); } diff --git a/server/src/domain/repositories/database.repository.ts b/server/src/domain/repositories/database.repository.ts index 55911e7ce5..09de8c00c0 100644 --- a/server/src/domain/repositories/database.repository.ts +++ b/server/src/domain/repositories/database.repository.ts @@ -48,6 +48,7 @@ export interface IDatabaseRepository { runMigrations(options?: { transaction?: 'all' | 'none' | 'each' }): Promise; withLock(lock: DatabaseLock, callback: () => Promise): Promise; tryLock(lock: DatabaseLock): Promise; + releaseLock(lock: DatabaseLock): Promise; isBusy(lock: DatabaseLock): boolean; wait(lock: DatabaseLock): Promise; } diff --git a/server/src/infra/repositories/database.repository.ts b/server/src/infra/repositories/database.repository.ts index b24602b899..3ce53fc238 100644 --- a/server/src/infra/repositories/database.repository.ts +++ b/server/src/infra/repositories/database.repository.ts @@ -200,7 +200,7 @@ export class DatabaseRepository implements IDatabaseRepository { res = await callback(); } finally { try { - await this.releaseLock(lock, queryRunner); + await this._releaseLock(lock, queryRunner); } finally { await queryRunner.release(); } @@ -215,6 +215,11 @@ export class DatabaseRepository implements IDatabaseRepository { return await this.acquireTryLock(lock, queryRunner); } + async releaseLock(lock: DatabaseLock): Promise { + const queryRunner = this.dataSource.createQueryRunner(); + return await this._releaseLock(lock, queryRunner); + } + isBusy(lock: DatabaseLock): boolean { return this.asyncLock.isBusy(DatabaseLock[lock]); } @@ -232,7 +237,7 @@ export class DatabaseRepository implements IDatabaseRepository { return lockResult[0].pg_try_advisory_lock; } - private async releaseLock(lock: DatabaseLock, queryRunner: QueryRunner): Promise { + private async _releaseLock(lock: DatabaseLock, queryRunner: QueryRunner): Promise { return queryRunner.query('SELECT pg_advisory_unlock($1)', [lock]); } } diff --git a/server/src/microservices/app.service.ts b/server/src/microservices/app.service.ts index 9262fe3e6c..623538e594 100644 --- a/server/src/microservices/app.service.ts +++ b/server/src/microservices/app.service.ts @@ -87,8 +87,7 @@ export class AppService { } async teardown() { - await this.libraryService.unwatchAll(); - + await this.libraryService.teardown(); await this.metadataService.teardown(); } } diff --git a/server/src/test-utils/utils.ts b/server/src/test-utils/utils.ts index 4e92cae7ce..b13a1af732 100644 --- a/server/src/test-utils/utils.ts +++ b/server/src/test-utils/utils.ts @@ -48,6 +48,9 @@ export const db = { if (deleteUsers) { await em.query(`DELETE FROM "users" CASCADE;`); } + + // Release all locks + await em.query('SELECT pg_advisory_unlock_all()'); }); }, disconnect: async () => { @@ -124,9 +127,6 @@ export const testApp = { }, reset: async (options?: ResetOptions) => { await db.reset(options); - await app.get(AppService).init(); - - await app.get(MicroAppService).init(); }, get: (member: any) => app.get(member), teardown: async () => { diff --git a/server/test/repositories/database.repository.mock.ts b/server/test/repositories/database.repository.mock.ts index 19e2df17a3..5ac7c75953 100644 --- a/server/test/repositories/database.repository.mock.ts +++ b/server/test/repositories/database.repository.mock.ts @@ -14,6 +14,7 @@ export const newDatabaseRepositoryMock = (): jest.Mocked => runMigrations: jest.fn(), withLock: jest.fn().mockImplementation((_, function_: () => Promise) => function_()), tryLock: jest.fn(), + releaseLock: jest.fn(), isBusy: jest.fn(), wait: jest.fn(), };