浏览代码

fix(core): Reset activeConfig on app shutdown

Michael Bromley 3 年之前
父节点
当前提交
8b8e310c05

+ 0 - 2
packages/core/e2e/fixtures/test-plugins/with-config.ts

@@ -6,12 +6,10 @@ import { ConfigModule, VendurePlugin } from '@vendure/core';
     configuration: config => {
         // tslint:disable-next-line:no-non-null-assertion
         config.defaultLanguageCode = LanguageCode.zh;
-        TestPluginWithConfig.configSpy();
         return config;
     },
 })
 export class TestPluginWithConfig {
-    static configSpy = jest.fn();
     static setup() {
         return TestPluginWithConfig;
     }

+ 0 - 22
packages/core/e2e/plugin.e2e-spec.ts

@@ -48,7 +48,6 @@ describe('Plugins', () => {
         const configService = server.app.get(ConfigService);
         expect(configService instanceof ConfigService).toBe(true);
         expect(configService.defaultLanguageCode).toBe(LanguageCode.zh);
-        expect(TestPluginWithConfig.configSpy).toHaveBeenCalledTimes(1);
     });
 
     it('extends the admin API', async () => {
@@ -138,24 +137,3 @@ describe('Plugins', () => {
         });
     });
 });
-
-describe('Multiple bootstraps in same process', () => {
-    const activeConfig = testConfig();
-    const { server, adminClient, shopClient } = createTestEnvironment({
-        ...activeConfig,
-        plugins: [TestPluginWithConfig.setup()],
-    });
-
-    beforeAll(async () => {
-        await server.init({
-            initialData,
-            productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
-            customerCount: 1,
-        });
-        await adminClient.asSuperAdmin();
-    }, TEST_SETUP_TIMEOUT_MS);
-
-    it('plugin `configure` function called only once', async () => {
-        expect(TestPluginWithConfig.configSpy).toHaveBeenCalledTimes(1);
-    });
-});

+ 0 - 12
packages/core/src/bootstrap.ts

@@ -156,13 +156,6 @@ export async function preBootstrapConfig(
     return config;
 }
 
-// This is here to prevent a plugin's `configure` function from executing more than once in the
-// same process. Running more than once can occur e.g. if a script runs the `runMigrations()` function
-// followed by the `bootstrap()` function, and will lead to very hard-to-debug errors caused by
-// mutating the config object twice, e.g. plugins pushing custom fields again resulting in duplicate
-// custom field definitions.
-const pluginConfigDidRun = new WeakSet<RuntimeVendureConfig['plugins'][number]>();
-
 /**
  * Initialize any configured plugins.
  */
@@ -170,12 +163,7 @@ async function runPluginConfigurations(config: RuntimeVendureConfig): Promise<Ru
     for (const plugin of config.plugins) {
         const configFn = getConfigurationFunction(plugin);
         if (typeof configFn === 'function') {
-            const configAlreadyRan = pluginConfigDidRun.has(plugin);
-            if (configAlreadyRan) {
-                continue;
-            }
             config = await configFn(config);
-            pluginConfigDidRun.add(plugin);
         }
     }
     return config;

+ 7 - 0
packages/core/src/config/config-helpers.ts

@@ -4,6 +4,13 @@ import { PartialVendureConfig, RuntimeVendureConfig } from './vendure-config';
 
 let activeConfig = defaultConfig;
 
+/**
+ * Reset the activeConfig object back to the initial default state.
+ */
+export function resetConfig() {
+    activeConfig = defaultConfig;
+}
+
 /**
  * Override the default config by merging in the supplied values. Should only be used prior to
  * bootstrapping the app.

+ 14 - 3
packages/core/src/config/config.service.ts

@@ -1,8 +1,8 @@
-import { DynamicModule, Injectable, Type } from '@nestjs/common';
+import { DynamicModule, Injectable, OnApplicationShutdown, Type } from '@nestjs/common';
 import { LanguageCode } from '@vendure/common/lib/generated-types';
 import { ConnectionOptions } from 'typeorm';
 
-import { getConfig } from './config-helpers';
+import { getConfig, resetConfig } from './config-helpers';
 import { CustomFields } from './custom-field/custom-field-types';
 import { EntityIdStrategy } from './entity-id-strategy/entity-id-strategy';
 import { Logger, VendureLogger } from './logger/vendure-logger';
@@ -25,7 +25,7 @@ import {
 } from './vendure-config';
 
 @Injectable()
-export class ConfigService implements VendureConfig {
+export class ConfigService implements VendureConfig, OnApplicationShutdown {
     private activeConfig: RuntimeVendureConfig;
 
     constructor() {
@@ -36,6 +36,17 @@ export class ConfigService implements VendureConfig {
         }
     }
 
+    /**
+     * When the application shuts down, we reset the activeConfig to the default. Usually this is
+     * redundant, as the app shutdown would normally coincide with the process ending. However, in some
+     * circumstances, such as when running migrations immediately followed by app bootstrap, the activeConfig
+     * will persist between these two applications and mutations e.g. to the CustomFields will result in
+     * hard-to-debug errors. So resetting is a precaution against this scenario.
+     */
+    onApplicationShutdown(signal?: string): any {
+        resetConfig();
+    }
+
     get apiOptions(): Required<ApiOptions> {
         return this.activeConfig.apiOptions;
     }