From 0863c227ad3e00239c68c35815af8fe01d9ee60c Mon Sep 17 00:00:00 2001 From: Igor Savin Date: Tue, 13 Jun 2023 12:24:46 +0300 Subject: [PATCH] Add enabled flag --- .github/dependabot.yml | 10 +-- .github/workflows/ci.yml | 1 - .github/workflows/coverage.yml | 1 - .github/workflows/linting.yml | 1 - README.md | 84 ++++++++++++++---- lib/awilixManager.ts | 7 +- package.json | 8 +- rollup.config.mjs | 2 +- test/awilixManager.spec.ts | 155 +++++++++++++++++++++++++++------ 9 files changed, 209 insertions(+), 60 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 97ed31c..e09c5f8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,16 +1,16 @@ version: 2 updates: - package-ecosystem: github-actions - directory: "/" + directory: '/' schedule: interval: daily open-pull-requests-limit: 10 - package-ecosystem: npm - directory: "/" + directory: '/' schedule: interval: daily open-pull-requests-limit: 10 ignore: - - dependency-name: "@typescript-eslint/eslint-plugin" - - dependency-name: "@typescript-eslint/parser" - - dependency-name: "@types/node" + - dependency-name: '@typescript-eslint/eslint-plugin' + - dependency-name: '@typescript-eslint/parser' + - dependency-name: '@types/node' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae77856..b1dd62f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,6 @@ jobs: - name: Run Tests run: npm run test:coverage - automerge: needs: build runs-on: ubuntu-latest diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 49c0eba..543a4a7 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,5 +1,4 @@ --- - name: coverage on: diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index d751c59..88657fb 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -1,5 +1,4 @@ --- - name: linting on: diff --git a/README.md b/README.md index 97d851d..7f7392b 100644 --- a/README.md +++ b/README.md @@ -21,32 +21,82 @@ import { AwilixManager } from 'awilix-manager' import { asClass, createContainer } from 'awilix' class AsyncClass { - async init() { - // init logic - } + async init() { + // init logic + } - async dispose() { - // dispose logic - } + async dispose() { + // dispose logic + } } const diContainer = createContainer({ - injectionMode: 'PROXY', + injectionMode: 'PROXY', }) diContainer.register( - 'dependency1', - asClass(AsyncClass, { - lifetime: 'SINGLETON', - asyncInitPriority: 10, // lower value means its initted earlier - asyncDisposePriority: 10, // lower value means its disposed earlier - asyncInit: 'init', - asyncDispose: 'dispose', - eagerInject: true, // this will be constructed and cached immediately - }), + 'dependency1', + asClass(AsyncClass, { + lifetime: 'SINGLETON', + asyncInitPriority: 10, // lower value means its initted earlier + asyncDisposePriority: 10, // lower value means its disposed earlier + asyncInit: 'init', + asyncDispose: 'dispose', + eagerInject: true, // this will be constructed and cached immediately. Redundant for resolves with `asyncInit` parameter set, as that is always resolved eagerly. + }), ) -const awilixManager = new AwilixManager() +const awilixManager = new AwilixManager({ + diContainer, + asyncInit: true, + asyncDispose: true, +}) await awilixManager.executeInit() // this will execute eagerInject and asyncInit await awilixManager.executeDispose() // this will execute asyncDispose ``` + +## Disabling eager injection conditionally + +In some cases you may want to prevent eager injection and async disposal of some of your dependencies - e. g. when you want to disable all of your background jobs or message consumers in some of your integration tests. +You can use `enabled` resolver parameter for that: + +```js +import { AwilixManager } from 'awilix-manager' +import { asClass, createContainer } from 'awilix' + +class QueueConsumerClass { + async consume() { + // consumer registration logic + } + + async destroy() { + // dispose logic + } +} + +const diContainer = createContainer({ + injectionMode: 'PROXY', +}) + +const isAMQPEnabled = false // disable consumers, e. g. for tests + +diContainer.register( + 'dependency1', + asClass(QueueConsumerClass, { + lifetime: 'SINGLETON', + asyncInitPriority: 10, // lower value means its initted earlier + asyncDisposePriority: 10, // lower value means its disposed earlier + asyncInit: 'consume', + asyncDispose: 'destroy', + enabled: isAMQPEnabled, // default is true + }), +) + +const awilixManager = new AwilixManager({ + diContainer, + asyncInit: true, + asyncDispose: true, +}) +await awilixManager.executeInit() // this will not execute asyncInit, because consumer is disabled +await awilixManager.executeDispose() // this will not execute asyncDispose, because consumer is disabled +``` diff --git a/lib/awilixManager.ts b/lib/awilixManager.ts index c12e940..1647548 100644 --- a/lib/awilixManager.ts +++ b/lib/awilixManager.ts @@ -8,6 +8,7 @@ declare module 'awilix' { asyncDispose?: boolean | string asyncDisposePriority?: number // lower means it gets disposed earlier eagerInject?: boolean + enabled?: boolean } } @@ -43,7 +44,7 @@ export class AwilixManager { export async function asyncInit(diContainer: AwilixContainer) { const dependenciesWithAsyncInit = Object.entries(diContainer.registrations) .filter((entry) => { - return entry[1].asyncInit + return entry[1].asyncInit && entry[1].enabled !== false }) .sort((entry1, entry2) => { const [key1, resolver1] = entry1 @@ -71,7 +72,7 @@ export async function asyncInit(diContainer: AwilixContainer) { export function eagerInject(diContainer: AwilixContainer) { const dependenciesWithEagerInject = Object.entries(diContainer.registrations).filter((entry) => { - return entry[1].eagerInject + return entry[1].eagerInject && entry[1].enabled !== false }) for (const entry of dependenciesWithEagerInject) { @@ -82,7 +83,7 @@ export function eagerInject(diContainer: AwilixContainer) { export async function asyncDispose(diContainer: AwilixContainer) { const dependenciesWithAsyncDispose = Object.entries(diContainer.registrations) .filter((entry) => { - return entry[1].asyncDispose + return entry[1].asyncDispose && entry[1].enabled !== false }) .sort((entry1, entry2) => { const [key1, resolver1] = entry1 diff --git a/package.json b/package.json index 5cbbd05..2318a18 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,9 @@ "devDependencies": { "@rollup/plugin-terser": "^0.4.3", "@rollup/plugin-typescript": "^11.1.1", - "@types/node": "^20.2.6", - "@typescript-eslint/eslint-plugin": "^5.59.9", - "@typescript-eslint/parser": "^5.59.9", + "@types/node": "^20.3.1", + "@typescript-eslint/eslint-plugin": "^5.59.11", + "@typescript-eslint/parser": "^5.59.11", "@vitest/coverage-v8": "^0.32.0", "del-cli": "^5.0.0", "eslint": "^8.42.0", @@ -36,7 +36,7 @@ "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-vitest": "^0.2.6", "prettier": "^2.8.8", - "rollup": "^3.24.1", + "rollup": "^3.25.1", "typescript": "^5.1.3", "vitest": "^0.32.0" }, diff --git a/rollup.config.mjs b/rollup.config.mjs index 002081c..7493ab8 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -51,6 +51,6 @@ export default [ }, ], plugins: [typescript()], - external: ['awilix-manager'] + external: ['awilix-manager'], }, ] diff --git a/test/awilixManager.spec.ts b/test/awilixManager.spec.ts index f4cff0c..a1a0eca 100644 --- a/test/awilixManager.spec.ts +++ b/test/awilixManager.spec.ts @@ -102,6 +102,44 @@ describe('awilixManager', () => { expect(dependency3.isInitted).toBe(true) }) + it('does bit execute asyncInit on registered dependencies if disabled', async () => { + const diContainer = createContainer({ + injectionMode: 'PROXY', + }) + diContainer.register( + 'dependency1', + asClass(AsyncInitClass, { + lifetime: 'SINGLETON', + asyncInit: true, + enabled: false, + }), + ) + diContainer.register( + 'dependency2', + asClass(AsyncInitClass, { + lifetime: 'SINGLETON', + asyncInit: true, + eagerInject: true, + }), + ) + diContainer.register( + 'dependency3', + asClass(AsyncInitClass, { + lifetime: 'SINGLETON', + asyncInit: 'asyncInit', + enabled: false, + }), + ) + + await asyncInit(diContainer) + + const { dependency1, dependency2, dependency3 } = diContainer.cradle + + expect(dependency1.isInitted).toBe(false) + expect(dependency2.isInitted).toBe(true) + expect(dependency3.isInitted).toBe(false) + }) + it('execute asyncInit on registered dependencies in defined order', async () => { isInittedGlobal = false const diContainer = createContainer({ @@ -126,7 +164,7 @@ describe('awilixManager', () => { const manager = new AwilixManager({ diContainer, - asyncInit: true + asyncInit: true, }) await manager.executeInit() @@ -141,25 +179,25 @@ describe('awilixManager', () => { injectionMode: 'PROXY', }) diContainer.register( - 'dependency2', - asClass(AsyncInitGetClass, { - lifetime: 'SINGLETON', - asyncInit: true, - asyncInitPriority: 1, - }), + 'dependency2', + asClass(AsyncInitGetClass, { + lifetime: 'SINGLETON', + asyncInit: true, + asyncInitPriority: 1, + }), ) diContainer.register( - 'dependency1', - asClass(AsyncInitSetClass, { - lifetime: 'SINGLETON', - asyncInit: true, - asyncInitPriority: 1, - }), + 'dependency1', + asClass(AsyncInitSetClass, { + lifetime: 'SINGLETON', + asyncInit: true, + asyncInitPriority: 1, + }), ) const manager = new AwilixManager({ diContainer, - asyncInit: true + asyncInit: true, }) await manager.executeInit() @@ -207,6 +245,46 @@ describe('awilixManager', () => { expect(dependency3.isDisposed).toBe(true) }) + it('does not execute asyncDispose on registered dependencies if disabled', async () => { + const diContainer = createContainer({ + injectionMode: 'PROXY', + }) + diContainer.register( + 'dependency1', + asClass(AsyncDisposeClass, { + lifetime: 'SINGLETON', + asyncDispose: true, + enabled: false, + }), + ) + diContainer.register( + 'dependency2', + asClass(AsyncDisposeClass, { + lifetime: 'SINGLETON', + asyncDispose: true, + }), + ) + diContainer.register( + 'dependency3', + asClass(AsyncDisposeClass, { + lifetime: 'SINGLETON', + asyncDispose: 'asyncDispose', + enabled: false, + }), + ) + + const manager = new AwilixManager({ + diContainer, + }) + await manager.executeDispose() + + const { dependency1, dependency2, dependency3 } = diContainer.cradle + + expect(dependency1.isDisposed).toBe(false) + expect(dependency2.isDisposed).toBe(true) + expect(dependency3.isDisposed).toBe(false) + }) + it('execute asyncDispose on registered dependencies in defined order', async () => { isInittedGlobal = false const diContainer = createContainer({ @@ -242,20 +320,20 @@ describe('awilixManager', () => { injectionMode: 'PROXY', }) diContainer.register( - 'dependency2', - asClass(AsyncDisposeGetClass, { - lifetime: 'SINGLETON', - asyncDispose: true, - asyncDisposePriority: 1, - }), + 'dependency2', + asClass(AsyncDisposeGetClass, { + lifetime: 'SINGLETON', + asyncDispose: true, + asyncDisposePriority: 1, + }), ) diContainer.register( - 'dependency1', - asClass(AsyncDisposeSetClass, { - lifetime: 'SINGLETON', - asyncDispose: true, - asyncDisposePriority: 1, - }), + 'dependency1', + asClass(AsyncDisposeSetClass, { + lifetime: 'SINGLETON', + asyncDispose: true, + asyncDisposePriority: 1, + }), ) await asyncDispose(diContainer) @@ -282,11 +360,34 @@ describe('awilixManager', () => { const manager = new AwilixManager({ diContainer, - eagerInject: true + eagerInject: true, }) manager.executeInit() expect(isInittedGlobal).toBe(true) }) + + it('does not inject dependencies eagerly if disabled', () => { + isInittedGlobal = false + const diContainer = createContainer({ + injectionMode: 'PROXY', + }) + diContainer.register( + 'dependency1', + asClass(InitSetClass, { + lifetime: 'SINGLETON', + eagerInject: true, + enabled: false, + }), + ) + + const manager = new AwilixManager({ + diContainer, + eagerInject: true, + }) + manager.executeInit() + + expect(isInittedGlobal).toBe(false) + }) }) })