0

so I have this code (simplified a bit) to connect to a database, I have DATABASE_URL wrong on purpose so I get an error. But what I do not understand is the reason for which I am getting UnhandledPromiseRejectionWarning.

Any ideas?

cheers!

try {
    startServer();
} catch (err) {
    console.log(err);
}




async function startServer () {
    try {
        await connectToDatabase;
    } catch ( err ) {
        throw err;
    }
}

const connectToDatabase = new Promise((resolve, reject) => {
    mongoose.connect(
        process.env.DATABASE_URL,
        {
            useNewUrlParser: true,
            useUnifiedTopology: true,
        }
    );
    const database = mongoose.connection;
    database.on(
        'error',
        err => reject(err)
    );
    database.once(
        'open',
        () => {
            console.log('Connected to database...');
            resolve(database);
        }
    );
});


Eclipse-
  • 51
  • 3
  • 11
  • 1
    startServer is an async function, in your try block you are not awaiting it. – Kevin.a Aug 11 '20 at 06:54
  • 2
    Also, here `await connectToDatabase;` did you missed calling the function first using `connectToDatabase()` ? – palaѕн Aug 11 '20 at 06:56
  • @Kevin.a so if I got you right, you meant I have to wrap my first try catch in another async function in order to be able to use await before `startServer()`. In that case wouldn't I have another unhandled promise (the one returned by the added async function)? – Eclipse- Aug 11 '20 at 06:59
  • @Kevin.a `connectToDatabase` is a promise not a function – Eclipse- Aug 11 '20 at 07:02

2 Answers2

1

mongoose.connect returns a promise.

So you need to change:

  const connectToDatabase = new Promise((resolve, reject) => {
    mongoose.connect(
      process.env.DATABASE_URL,
      {
        useNewUrlParser: true,
        useUnifiedTopology: true
      }
    )
      .then(() => {
        const database = mongoose.connection
       
        database.on('error', err => {
          logError(err);
        });
        database.once(
          'open',
          () => {
            console.log('Connected to database...')
            resolve(database)
          }
        )
      })
      .catch(reject)
  })

You should improve this code:

        database.on('error', err => {
          logError(err);
        });

because this event is triggered whenever there is an error after the connection has been established, like a disconnection.

So you can't reject a promise that has been already resolved with the open event. You should configure the reconnection

Manuel Spigolon
  • 11,003
  • 5
  • 50
  • 73
  • Thank you for your answer. You are perfectly right about the last statement, since the error can occur after the promise has been resolved. So I should try to handle the future errors if any should happen. But I am curious, in this particular case the promise will never resolve since `DATABASE_URL` is wrong. And besides that, now that I am using another catch after `mongoose.connect()` promise, I am still getting the same old unhandled promise warning. – Eclipse- Aug 11 '20 at 07:51
  • 1
    Did you add the `.catch(reject)` too? It is at the end, after the `then` – Manuel Spigolon Aug 11 '20 at 07:53
  • Actually the catch on the connect method did the job, I didn't particularly use your exact approach, but I could solve the problem, thanks. – Eclipse- Aug 11 '20 at 08:48
1

By doing this: const connectToDatabase = new Promise((resolve, reject) => {... you are building a Promise on top level, before awaiting for it in the startServer. It's an equivalent of doing this:

// Top level Promise rejection
Promise.reject('error');

The rest of the code still works because await works on a already-resolved Promise (also, maybe the Promise has not resolved yet when awaited) but you should build the Promise inside a function instead:

try {
    startServer();
} catch (err) {
    console.log(err);
}

async function startServer () {
    try {
        await connectToDatabase();
    } catch ( err ) {
        throw err;
    }
}

function connectToDatabase() {
    return new Promise((resolve, reject) => {
        mongoose.connect(
            process.env.DATABASE_URL, {
            useNewUrlParser: true,
            useUnifiedTopology: true,
        });
        const database = mongoose.connection;
        database.on(
            'error',
            err => reject(err));
        database.once(
            'open',
            () => {
            console.log('Connected to database...');
            resolve(database);
        });
    });
}

With this, you get a reference on the new Promise only in startServer immediately after it is created, then it resolves or rejects and the possible rejection is caught and doesn't bubble up to the top level.

Guerric P
  • 30,447
  • 6
  • 48
  • 86