当前位置: 首页 > 知识库问答 >
问题:

使用AWS参数存储的NestJs TypeORM配置

充培
2023-03-14

NestJS的新手,遇到了一个问题。对于我们的部署,我们需要从AWS Parameter Store(Systems Manager)获取配置,包括数据库连接字符串。我有一个配置模块和配置服务,它基于参数存储路径检索我的环境的所有参数存储项:

这是我的配置服务:

import * as dotenv from 'dotenv';
import * as fs from 'fs';
import * as AWS from 'aws-sdk';

export class ConfigService {
    private readonly envConfig: { [key: string]: string };
    private awsParamStoreEntries: { [key: string]: string }[];

    constructor(awsParamStorePath: string, filePath: string) {
        this.envConfig = dotenv.parse(fs.readFileSync(filePath));

        this.loadAwsParameterStoreEntries(awsParamStorePath).then((data) => {
            this.awsParamStoreEntries = data;
        });
    }

    loadAwsParameterStoreEntries(pathPrefix: string) {
        const credentials = new AWS.SharedIniFileCredentials({ profile: 'grasshopper-parameter' });
        AWS.config.credentials = credentials;
        const ssm = new AWS.SSM({ region: 'us-west-2' });
        var params: { [key: string]: string }[] = [];

        return getParams({
            Path: '/app/v3/development/',
            Recursive: true,
            WithDecryption: true,
            MaxResults: 10,
        }).then(() => {
            return params;
        });

        function getParams(options) {
            return new Promise((resolve, reject) => {
                ssm.getParametersByPath(options, processParams(options, (err, data) => {
                    if (err) {
                        return reject(err);
                    }
                    resolve(data);
                }));
            });
        }

        function processParams(options, cb) {
            return function (err, data) {
                if (err) {
                    return cb(err)
                };
                data.Parameters.forEach(element => {
                    let key = element.Name.split('/').join(':')
                    params.push({ key: key, value: element.Value });
                });
                if (data.NextToken) {
                    const nextOptions = Object.assign({}, options);
                    nextOptions.NextToken = data.NextToken;
                    return ssm.getParametersByPath(nextOptions, processParams(options, cb));
                }
                return cb(null);
            };
        }
    }

    get(key: string): string {
        return this.envConfig[key];
    }

    getParamStoreValue(key: string): string {
        return this.awsParamStoreEntries.find(element => element.key === key)['value'];
    }

    getDatabase(): string {
        return this.awsParamStoreEntries.find(element => element.key === 'ConnectionStrings:CoreDb')['value'];
    }
}

下面是主要的应用模块声明块:

@Module({
  imports: [ConfigModule, TypeOrmModule.forRootAsync({
    imports: [ConfigModule],
    useFactory: async (configService: ConfigService) => ({
      url: configService.getDatabase()
    }),
    inject: [ConfigService]
  }),
    CoreModule, AuthModule],
  controllers: [AppController],
  providers: [AppService],
})

如您所见,我正在告诉TypeForm在ConfigService中调用getDatabase()方法,但问题是加载参数存储条目需要3-4秒,因此出现“未定义”错误,因为TypeForm尝试加载连接字符串时“this.awsParamStoreEntries”仍然未定义。

我在网上搜索了一下,看看是否已经这样做了,但是找不到任何以这种方式使用NestJS/TypeORM/AWS参数存储的东西。这里还有一个关于StackOverflow的现有(未回答)问题。

谢谢!

共有2个答案

金正阳
2023-03-14

我们可以使用异步提供者。

将AWS SSM param store参数与NestJS配置服务一起使用的工作项目示例:

创建异步提供程序:

import * as AWS from 'aws-sdk';
import { Parameter } from 'aws-sdk/clients/ssm';

export const ssmProvider = {
  provide: 'AWS_SSM',
  useFactory: async (): Promise<Parameter[]> => {
    const ssmClient = new AWS.SSM({
      endpoint: 'endpoint',
      region: 'us-west-2',
    });
    const result = await ssmClient
      .getParametersByPath({
        Path: '/ssm/path',
        Recursive: true,
      })
      .promise();
    return result?.Parameters;
  },
};

然后,我们可以使用该提供程序来注入值。

例如,在配置服务中注入AWS SSM参数:

export class ConfigModule {
  static register(options: ConfigModuleOptions): DynamicModule {
    return {
      global: true,
      module: ConfigModule,
      providers: [
        ssmProvider,
        {
          provide: CONFIG_OPTIONS,
          useValue: options,
        },
        ConfigService,
      ],
      exports: [ConfigService],
    };
  }
}

在配置服务构造函数中:

constructor(
    @Inject(CONFIG_OPTIONS) options: ConfigOptions,
    @Inject('AWS_SSM') awsParameters: Parameter[],
  ) {}

编辑:NPM软件包,它提供在应用程序启动时加载aws参数store参数的服务:

参数-store服务

孔礼骞
2023-03-14

你能这样做吗。

import { TypeOrmOptionsFactory, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ConfigService } from './config.service';
import { Injectable } from '@nestjs/common';

@Injectable()
export class TypeOrmConfigService implements TypeOrmOptionsFactory {
    constructor(private readonly configService: ConfigService) {
    }

    async createTypeOrmOptions(): Promise<TypeOrmModuleOptions> {
        this.configService.awsParamStoreEntries = await this.configService.loadAwsParameterStoreEntries(this.configService.awsParamStorePath);

        return {
            url: this.configService.getDatabase(),
        };
    }
}
@Module({
  imports: [
    ConfigModule, 
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useClass: TypeOrmConfigService,
    }),
    CoreModule, 
    AuthModule
  ],
  controllers: [AppController],
  providers: [AppService],
})
import * as dotenv from 'dotenv';
import * as fs from 'fs';
import * as AWS from 'aws-sdk';
import { Injectable } from '@nestjs/common';

@Injectable()
export class ConfigService {
    private readonly envConfig: { [key: string]: string };
    awsParamStoreEntries: { [key: string]: string }[];
    private readonly awsParamStorePath: string;

    constructor(awsParamStorePath: string, filePath: string) {
        this.envConfig = dotenv.parse(fs.readFileSync(filePath));
        this.awsParamStorePath = awsParamStorePath;
    }

    loadAwsParameterStoreEntries(pathPrefix: string) {...

https://docs.nestjs.com/techniques/database

 类似资料:
  • 还尝试将从中排除,但仍然不起作用。 例外 原因:org.springframework.beans.beanInstantiationException:未能实例化[com.amazonaws.services.SimpleSystemsManagement.awsSimpleSystemsManagement]:工厂方法'SSM Client'引发异常;嵌套异常是com.amazonaws.sd

  • 问题内容: 在哪里可以在客户端存储配置参数?我无法将参数存储在Servlet初始化参数(web.xml)中(因为我必须使用PHP)。那么如何在客户端存储初始化应用程序参数(例如PHP脚本位置,一些密码等)? 问题答案: 为此,您有以下选择: 将数据存储在客户端代码中。GWT会编译为javascript,最简单的方法是创建一个具有硬编码值的类。 在浏览器中存储数据。您可以使用Cookie或HTML5

  • IdentityServer 是为可扩展性设计的,其中一个扩展点是其所需数据的存储机制。该快速入门展示了如何配置 IdentityServer 以使用 EntityFramework(EF)作为其数据存储机制(取代目前为止我们一直使用的内存实现)。 IdentityServer4.EntityFramework 我们将移动到数据库的数据有两种,第一种是配置数据(资源 resources 和客户端

  • 问题内容: 有人可以让我知道为什么下面的代码仅从参数存储中获取一些条目吗? 问题答案: GetParametersByPath是一个分页的操作。每次调用后,您必须从结果对象中检索,如果它不是null也不为空,则必须进行另一个调用,并将其添加到请求中。 这是一个使用的示例,它具有相同的行为:

  • 问题内容: 我已经使用PDO一段时间了,并且正在重构一个项目,以便它使用存储的proc而不是内联SQL。我收到一个我无法解释的错误。我正在使用PHP版本5.3.5和MySQL版本5.0.7。 我只是想获得一个带有输出的基本存储过程。这是存储的过程: 这是我用来调用proc的代码,$ db是PDO的一个实例: 简单吧?但是,它导致以下错误: 如果我直接这样调用proc: 它按预期工作,这使我相信PH

  • KeyValueStore is an alternative OSD backend compared to FileStore. Currently, it uses LevelDB as backend. KeyValueStore doesn’t need journal device. Each operation will flush into the backend directly