Browse Source

refactor(core): Move InjectableStrategy lifecycle fns into ConfigModule

This allows the `init` and `destroy` hooks to also get called in the worker process
Michael Bromley 5 years ago
parent
commit
cd66713b18

+ 3 - 112
packages/core/src/app.module.ts

@@ -1,17 +1,7 @@
-import {
-    MiddlewareConsumer,
-    Module,
-    NestModule,
-    OnApplicationBootstrap,
-    OnApplicationShutdown,
-} from '@nestjs/common';
-import { ModuleRef } from '@nestjs/core';
+import { MiddlewareConsumer, Module, NestModule, OnApplicationShutdown } from '@nestjs/common';
 import { RequestHandler } from 'express';
 
 import { ApiModule } from './api/api.module';
-import { ConfigurableOperationDef } from './common/configurable-operation';
-import { Injector } from './common/injector';
-import { InjectableStrategy } from './common/types/injectable-strategy';
 import { ConfigModule } from './config/config.module';
 import { ConfigService } from './config/config.service';
 import { Logger } from './config/logger/vendure-logger';
@@ -31,17 +21,8 @@ import { ProcessContextModule } from './process-context/process-context.module';
         HealthCheckModule,
     ],
 })
-export class AppModule implements NestModule, OnApplicationBootstrap, OnApplicationShutdown {
-    constructor(
-        private configService: ConfigService,
-        private i18nService: I18nService,
-        private moduleRef: ModuleRef,
-    ) {}
-
-    async onApplicationBootstrap() {
-        await this.initInjectableStrategies();
-        await this.initConfigurableOperations();
-    }
+export class AppModule implements NestModule, OnApplicationShutdown {
+    constructor(private configService: ConfigService, private i18nService: I18nService) {}
 
     configure(consumer: MiddlewareConsumer) {
         const { adminApiPath, shopApiPath, middleware } = this.configService.apiOptions;
@@ -58,8 +39,6 @@ export class AppModule implements NestModule, OnApplicationBootstrap, OnApplicat
     }
 
     async onApplicationShutdown(signal?: string) {
-        await this.destroyInjectableStrategies();
-        await this.destroyConfigurableOperations();
         if (signal) {
             Logger.info('Received shutdown signal:' + signal);
         }
@@ -81,92 +60,4 @@ export class AppModule implements NestModule, OnApplicationBootstrap, OnApplicat
         }
         return result;
     }
-
-    private async initInjectableStrategies() {
-        const injector = new Injector(this.moduleRef);
-        for (const strategy of this.getInjectableStrategies()) {
-            if (typeof strategy.init === 'function') {
-                await strategy.init(injector);
-            }
-        }
-    }
-
-    private async destroyInjectableStrategies() {
-        for (const strategy of this.getInjectableStrategies()) {
-            if (typeof strategy.destroy === 'function') {
-                await strategy.destroy();
-            }
-        }
-    }
-
-    private async initConfigurableOperations() {
-        const injector = new Injector(this.moduleRef);
-        for (const operation of this.getConfigurableOperations()) {
-            await operation.init(injector);
-        }
-    }
-
-    private async destroyConfigurableOperations() {
-        for (const operation of this.getConfigurableOperations()) {
-            await operation.destroy();
-        }
-    }
-
-    private getInjectableStrategies(): InjectableStrategy[] {
-        const {
-            assetNamingStrategy,
-            assetPreviewStrategy,
-            assetStorageStrategy,
-        } = this.configService.assetOptions;
-        const { productVariantPriceCalculationStrategy } = this.configService.catalogOptions;
-        const { adminAuthenticationStrategy, shopAuthenticationStrategy } = this.configService.authOptions;
-        const { taxZoneStrategy } = this.configService.taxOptions;
-        const { jobQueueStrategy } = this.configService.jobQueueOptions;
-        const {
-            mergeStrategy,
-            checkoutMergeStrategy,
-            orderItemPriceCalculationStrategy,
-            process,
-            orderCodeStrategy,
-            stockAllocationStrategy,
-        } = this.configService.orderOptions;
-        const { entityIdStrategy } = this.configService;
-        return [
-            ...adminAuthenticationStrategy,
-            ...shopAuthenticationStrategy,
-            assetNamingStrategy,
-            assetPreviewStrategy,
-            assetStorageStrategy,
-            taxZoneStrategy,
-            jobQueueStrategy,
-            mergeStrategy,
-            checkoutMergeStrategy,
-            orderCodeStrategy,
-            entityIdStrategy,
-            productVariantPriceCalculationStrategy,
-            orderItemPriceCalculationStrategy,
-            ...process,
-            stockAllocationStrategy,
-        ];
-    }
-
-    private getConfigurableOperations(): Array<ConfigurableOperationDef<any>> {
-        const { paymentMethodHandlers } = this.configService.paymentOptions;
-        const { collectionFilters } = this.configService.catalogOptions;
-        const { promotionActions, promotionConditions } = this.configService.promotionOptions;
-        const {
-            shippingCalculators,
-            shippingEligibilityCheckers,
-            fulfillmentHandlers,
-        } = this.configService.shippingOptions;
-        return [
-            ...paymentMethodHandlers,
-            ...collectionFilters,
-            ...(promotionActions || []),
-            ...(promotionConditions || []),
-            ...(shippingCalculators || []),
-            ...(shippingEligibilityCheckers || []),
-            ...(fulfillmentHandlers || []),
-        ];
-    }
 }

+ 7 - 1
packages/core/src/common/types/injectable-strategy.ts

@@ -12,13 +12,19 @@ export interface InjectableStrategy {
      * @description
      * Defines setup logic to be run during application bootstrap. Receives
      * the {@link Injector} as an argument, which allows application providers
-     * to be used as part of the setup.
+     * to be used as part of the setup. This hook will be called on both the
+     * main server and the worker processes. If you have code which should only
+     * run on either the server on the worker, then inject the {@link ProcessContext}
+     * to check the current context.
      *
      * @example
      * ```TypeScript
      * async init(injector: Injector) {
+     *   const processContext = injector.get(ProcessContext);
+     *   if (processContext.isServer) {
      *     const myService = injector.get(MyService);
      *     await myService.doSomething();
+     *   }
      * }
      * ```
      */

+ 126 - 3
packages/core/src/config/config.module.ts

@@ -1,6 +1,10 @@
-import { Module } from '@nestjs/common';
+import { Module, OnApplicationBootstrap, OnApplicationShutdown } from '@nestjs/common';
+import { ModuleRef } from '@nestjs/core';
 
-import { I18nService } from '../i18n/i18n.service';
+import { ConfigurableOperationDef } from '../common/configurable-operation';
+import { Injector } from '../common/injector';
+import { InjectableStrategy } from '../common/types/injectable-strategy';
+import { ProcessContext } from '../process-context/process-context';
 
 import { ConfigService } from './config.service';
 
@@ -8,4 +12,123 @@ import { ConfigService } from './config.service';
     providers: [ConfigService],
     exports: [ConfigService],
 })
-export class ConfigModule {}
+export class ConfigModule implements OnApplicationBootstrap, OnApplicationShutdown {
+    constructor(
+        private configService: ConfigService,
+        private moduleRef: ModuleRef,
+        private processContext: ProcessContext,
+    ) {}
+
+    async onApplicationBootstrap() {
+        if (this.runInjectableStrategyLifecycleHooks()) {
+            await this.initInjectableStrategies();
+            await this.initConfigurableOperations();
+        }
+    }
+
+    async onApplicationShutdown(signal?: string) {
+        if (this.runInjectableStrategyLifecycleHooks()) {
+            await this.destroyInjectableStrategies();
+            await this.destroyConfigurableOperations();
+        }
+    }
+
+    /**
+     * The lifecycle hooks of the configured strategies should be run if we are on the main
+     * server process _or_ if we are on the worker running independently of the main process.
+     */
+    private runInjectableStrategyLifecycleHooks(): boolean {
+        return (
+            this.processContext.isServer ||
+            (this.processContext.isWorker && !this.configService.workerOptions.runInMainProcess)
+        );
+    }
+
+    private async initInjectableStrategies() {
+        const injector = new Injector(this.moduleRef);
+        for (const strategy of this.getInjectableStrategies()) {
+            if (typeof strategy.init === 'function') {
+                await strategy.init(injector);
+            }
+        }
+    }
+
+    private async destroyInjectableStrategies() {
+        for (const strategy of this.getInjectableStrategies()) {
+            if (typeof strategy.destroy === 'function') {
+                await strategy.destroy();
+            }
+        }
+    }
+
+    private async initConfigurableOperations() {
+        const injector = new Injector(this.moduleRef);
+        for (const operation of this.getConfigurableOperations()) {
+            await operation.init(injector);
+        }
+    }
+
+    private async destroyConfigurableOperations() {
+        for (const operation of this.getConfigurableOperations()) {
+            await operation.destroy();
+        }
+    }
+
+    private getInjectableStrategies(): InjectableStrategy[] {
+        const {
+            assetNamingStrategy,
+            assetPreviewStrategy,
+            assetStorageStrategy,
+        } = this.configService.assetOptions;
+        const { productVariantPriceCalculationStrategy } = this.configService.catalogOptions;
+        const { adminAuthenticationStrategy, shopAuthenticationStrategy } = this.configService.authOptions;
+        const { taxZoneStrategy } = this.configService.taxOptions;
+        const { jobQueueStrategy } = this.configService.jobQueueOptions;
+        const {
+            mergeStrategy,
+            checkoutMergeStrategy,
+            orderItemPriceCalculationStrategy,
+            process,
+            orderCodeStrategy,
+            stockAllocationStrategy,
+        } = this.configService.orderOptions;
+        const { entityIdStrategy } = this.configService;
+        return [
+            ...adminAuthenticationStrategy,
+            ...shopAuthenticationStrategy,
+            assetNamingStrategy,
+            assetPreviewStrategy,
+            assetStorageStrategy,
+            taxZoneStrategy,
+            jobQueueStrategy,
+            mergeStrategy,
+            checkoutMergeStrategy,
+            orderCodeStrategy,
+            entityIdStrategy,
+            productVariantPriceCalculationStrategy,
+            orderItemPriceCalculationStrategy,
+            ...process,
+            stockAllocationStrategy,
+        ];
+    }
+
+    private getConfigurableOperations(): Array<ConfigurableOperationDef<any>> {
+        const { paymentMethodHandlers } = this.configService.paymentOptions;
+        const { collectionFilters } = this.configService.catalogOptions;
+        const { promotionActions, promotionConditions } = this.configService.promotionOptions;
+        const {
+            shippingCalculators,
+            shippingEligibilityCheckers,
+            fulfillmentHandlers,
+        } = this.configService.shippingOptions;
+        return [
+            ...paymentMethodHandlers,
+            ...collectionFilters,
+            ...(promotionActions || []),
+            ...(promotionConditions || []),
+            ...(shippingCalculators || []),
+            ...(shippingEligibilityCheckers || []),
+            ...(fulfillmentHandlers || []),
+        ];
+    }
+}