简体   繁体   中英

How do I solve a problem with my DB connection and require?

I have an Express app that was created with express generator. I have a standard app.js file that exports app. I also have a standard www file that imports app and is a starting point of the application:

const app = require('../app')
const debug = require('debug')('img-final:server')
const http = require('http')
const Mongo = require('../utils/dbConnection/dbConnection')
const port = normalizePort(process.env.PORT || '3000')
app.set('port', port)

/**
 * Create HTTP server.
 */
const server = http.createServer(app)

/**
 * Listen on provided port, on all network interfaces.
 */

async function startServer() {
  try {
    await Mongo.init()
    debug('Connected correctly to DB')
    server.listen(port)
  } catch (err) {
    debug(err)
  }
}

startServer()

//some more unrelated code. 

I also have a utility file for connecting to db dbConnection.js :

const MongoClient = require('mongodb').MongoClient

class Mongo {
  async init() {
    const client = new MongoClient(`mongodb://localhost:27017/img-new`, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    })
    await client.connect()
    this.db = client.db('img-new')
  }

  getConnection() {
    return this.db
  }
}

module.exports = new Mongo()

My problem is that when I start my app const app = require('../app') is obviously running first, and wherever in my app route controllers I use getConnection() , the connection is undefined at that point because my Mongo.init() is running after const app = require('../app') .

I'm trying to understand how to solve it in sane way. I guess I can move all require 's and all other code inside startServer after await Mongo.init() , but it seems like there should be a better solution. Thank you.

Edit: Is this an OK solution?

const debug = require('debug')('img-final:server')
const http = require('http')
const Mongo = require('../utils/dbConnection/dbConnection')



async function startServer() {
  try {
    await Mongo.init()

    const app = require('../app')
    
    const port = normalizePort(process.env.PORT || '3000')
    app.set('port', port)
    const server = http.createServer(app)
    server.listen(port)

  } catch (err) {
    debug(err)
  }
}

startServer()

I have 1 solution but I'm not sure it satisfies your expectation.

In the getConenction method you check if this.db is undefined . If it's a case, just call init() method then return this.db . If not, you return this.db directly. The code is like this:

 async getConnection() {
    if(!this.db) {
         // connection to db is not established yet, we call `init` method
         await this.init();
    }
    
    // this.db is defined here, we return the connection
    return this.db;
  }

And you don't have to call await Mongo.init() in the startServer() function

The previous answer by Đăng Khoa Đinh is the right direction. I add a bit of defensive coding to prevent multiple this.init() being called at the same time. Note: I did not code against errors while connecting.

const MongoClient = require('mongodb').MongoClient

class Mongo {

    init() {

        // Gerard we set isConnected to a promise
        this.isConnected = new Promise(async (resolve, reject) => {

            const client = new MongoClient(`mongodb://localhost:27017/img-new`, {
                useNewUrlParser: true,
                useUnifiedTopology: true,
            })
            await client.connect()
            this.db = client.db('img-new')
            resolve();

        });
    }

    isConnected = null;

    async getConnection() {
        if(this.isConnected === null) {
            // connection to db is not established yet, we call `init` method
            this.init();
        }

        // Now either the DB is already connected, or a connection is in progress. We wait.
        await this.isConnected;

        // this.db is defined here, we return the connection
        return this.db;
    }
}

module.exports = new Mongo()

The caller will then just do

connection = await Mongo.getConnection();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM