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

1

7

I'm using:

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

Borchers answered 17/7, 2020 at 9:23 Comment(1)
Are you sure the problem is related to Aurora and not to Lambda? It feels to me that the connection remains open after cold start, and since you don't store the connection, every successive call createConnection attempts to create a new TypeORM connection with the same name, thus fails.Plenty
M
9

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;
  }
}
Mandel answered 6/12, 2020 at 22:0 Comment(1)
With the deprecation of ConnectionManager, is there an updated solution for this? github.com/typeorm/typeorm/issues/8010Microsecond

© 2022 - 2024 — McMap. All rights reserved.