Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage typeORM connection of Aurora Serverless data api inside Lambda using Serverless Framework

I'm using:

  • Aurora Serverless Data API (Postgres)
  • TypeORM with typeorm-aurora-data-api-driver
  • AWS Lambda with Serverless framework (TypeScript, WebPack)

I'm connecting to the db like it's described in github,

const connection = await createConnection({
      type: 'aurora-data-api-pg',
      database: 'test-db',
      secretArn: 'arn:aws:secretsmanager:eu-west-1:537011205135:secret:xxxxxx/xxxxxx/xxxxxx',
      resourceArn: 'arn:aws:rds:eu-west-1:xxxxx:xxxxxx:xxxxxx',
      region: 'eu-west-1'
    })

And this is how I use it inside of my Lambda function

export const testConfiguration: APIGatewayProxyHandler = async (event, _context) => {
  let response;
  try {
    const connectionOptions: ConnectionOptions = await getConnectionOptions();
    const connection = await createConnection({
      ...connectionOptions,
      entities,
    });
    const userRepository = connection.getRepository(User);
    const users = await userRepository.find();

    response = {
      statusCode: 200,
      body: JSON.stringify({ users }),
    };
  } catch (e) {
    response = {
      statusCode: 500,
      body: JSON.stringify({ error: 'server side error' }),
    };
  }
  return response;
};

When I execute is first time it works just well.

But second and next times I'm getting an error

AlreadyHasActiveConnectionError: Cannot create a new connection named "default", because connection with such name already exist and it now has an active connection session.

So, what is the proper way to manage this connection? Should it be somehow reused?

I've found some resolutions for simple RDS but the whole point of Aurora Serverless Data API is that you don't have to manage the connection

like image 850
Ivan Avatar asked Jul 17 '20 09:07

Ivan


1 Answers

when you try to establish a connection, you need to check if there is already a connection it can use. this is my Database class used to handle connections

export default class Database {
  private connectionManager: ConnectionManager;

  constructor() {
    this.connectionManager = getConnectionManager();
  }

  async getConnection(): Promise<Connection> {
    const CONNECTION_NAME = 'default';

    let connection: Connection;

    if (this.connectionManager.has(CONNECTION_NAME)) {
      logMessage(`Database.getConnection()-using existing connection::: ${CONNECTION_NAME}`);
      connection = await this.connectionManager.get(CONNECTION_NAME);

      if (!connection.isConnected) {
        connection = await connection.connect();
      }
    } else {
      logMessage('Database.getConnection()-creating connection ...');
      logMessage(`DB host::: ${process.env.DB_HOST}`);

      const connectionOptions: ConnectionOptions = {
        name: CONNECTION_NAME,
        type: 'postgres',
        port: 5432,
        logger: 'advanced-console',
        logging: ['error'],
        host: process.env.DB_HOST,
        username: process.env.DB_USERNAME,
        database: process.env.DB_DATABASE,
        password: process.env.DB_PASSWORD,
        namingStrategy: new SnakeNamingStrategy(),
        entities: Object.keys(entities).map((module) => entities[module]),
      };

      connection = await createConnection(connectionOptions);
    }

    return connection;
  }
}
like image 89
mlg87 Avatar answered Sep 21 '22 03:09

mlg87