Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gracefully closing connection of DB using TypeORM in NestJs

So, before I go deep in the problem let me explain you the basic of my app.

I have connection to DB(TypeOrm), Kafka(kafkajs) in my app.

My app is the Consumer of 1 topic which:

  1. Gets some data in the callback handler, and puts that data in one table using TypeORM Entity
  2. Maintains the Global map (in some Singleton Instance of a class) with some id (that I get in data of point 1).

At the time of app getting shutdown, my task is:

  1. Disconnect all the consumers of the topics (this service is connected to) from the Kafka
  2. Traverse the Global Map (point 2) and repark the message in the some topic
  3. Disconnect the DB connections using the close method.

Here are some piece of code that might help you understand how I added the life cycle events on Server in NestJs.

system.server.life.cycle.events.ts

@Injectable()
export class SystemServerLifeCycleEventsShared implements BeforeApplicationShutdown {
    constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger, private readonly someService: SomeService) {}

    async beforeApplicationShutdown(signal: string) {
        const [err] = await this.someService.handleAbruptEnding();

        if (err) this.logger.info(`beforeApplicationShutdown, error::: ${JSON.stringify(err)}`);
        this.logger.info(`beforeApplicationShutdown, signal ${signal}`);
    }
}

some.service.ts

export class SomeService {
    constructor(private readonly kafkaConnector: KafkaConnector, private readonly postgresConnector: PostgresConnector) {}
    
    public async handleAbruptEnding(): Promise<any> {
        
        await this.kafkaConnector.disconnectAllConsumers();
        for(READ_FROM_GLOBAL_STORE) { 
             await this.kafkaConnector.function.call.to.repark.the.message();
        }
        
        await this.postgresConnector.disconnectAllConnections();

        return true;
    }
}

postgres.connector.ts

export class PostgresConnector {
    private connectionManager: ConnectionManager; 
    constructor () {
        this.connectionManager = getConnectionManager();
    }

    public async disconnectAllConnections(): Promise<void[]> {
        const connectionClosePromises: Promise<void> = [];
        connectionManager.connections?.forEach((connection) => {
            if (connection.isConnected) connectionClosePromises.push(connection.close());
        });

        return Promise.all(connectionClosePromises);
    }
}

ConnectionManager& getConnectionManager() imported from TypeORM module.

Now here are some unusual exceptions / behavior I am facing:

  1. Disconnect all connections is throwing exception/error as in quote:

    ERROR [TypeOrmModule] Cannot execute operation on "default" connection because connection is not yet established. If connection is not yet established then how come my isConnected came true inside of if. I am not getting any clue anywhere how is this possible. And how to do graceful shutdown of the connection in TypeORM.

  2. Do we really need to handle the closure of the connection in TypeORM or it internally handles it.

  3. Even if, TypeORM handles the connection closure internally, how could we achieve it explicitly.

  4. Is there any callback that can be triggered in case the connection is disconnected properly so that I am sure, that disconnection actually happened from the db.

  5. Some of the messages are coming after I press CTRL + C (mimicking the abrupt/closure of the process of my server) and the control comes back to Terminal. This means, some thread is coming back after the handle returns to my terminal (🤷, no clue, how would I handle this, since if you see, my handleAbruptHandling is awaited and also, I cross checked all the promises are being awaited properly.)

Some of the things to know:

  1. I properly added my module to create the hooks of server life cycle events.
  2. Injected the objects in almost all the classes properly.
  3. Not getting any DI issue from NEST and server is getting started properly.

Please shed some light and let me know how can I gracefully disconnect from db using typeorm api inside NestJs in case of abrupt closure.

Thanks in advance and happy coding :)

like image 744
Ankur Verma Avatar asked Oct 23 '25 06:10

Ankur Verma


1 Answers

Littlebit late but may help someone..

You are missing the param keepConnectionAlive as true in TypeOrmModuleOptions, typeOrm dont keep connections alive as default. I set keepConnectionAlive as false, if a transaction keeps the connection open im going to close the connection (typeorm wait until the transaction or other process finish before close the connection), this is my implementation

import { Logger, Injectable, OnApplicationShutdown } from '@nestjs/common';
import { getConnectionManager } from 'typeorm';

@Injectable()
export class LifecyclesService implements OnApplicationShutdown {
  private readonly logger = new Logger();

  onApplicationShutdown(signal: string) {
    this.logger.warn('SIGNTERM: ', signal);
    this.closeDBConnection();
  }

  closeDBConnection() {
    const conn = getConnectionManager().get();

    if (conn.isConnected) {
      conn
        .close()
        .then(() => {
          this.logger.log('DB conn closed');
        })
        .catch((err: any) => {
          this.logger.error('Error clossing conn to DB, ', err);
        });
    } else {
      this.logger.log('DB conn already closed.');
    }
  }
}
like image 56
Camilo Andres Elgueta Basso Avatar answered Oct 26 '25 03:10

Camilo Andres Elgueta Basso