question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

When to client.end with promises syntax

See original GitHub issue

I use node 8.11.1, express 4.16.3, pg 7.4.2. So, I am using a Client to connect to the database, with certain privileges and signup new users. I am using promises syntax for my function. I don’t know when to client.end() when everything goes well. In the docs I dont see a client.end() with the promise syntax. So, here is my function

const signup =  (user) => {
  return new Promise((resolved, rejeted)=>{
    getUser(user.email)
    .then(res => {
      if (!res) {//email taken
        client.end();
        return resolved(false);
      }
      return res; //true if email not taken
    })
    .then(res=>{
        return crypto.hashPassword(user.password); //return hashed password
    })
    .then(res=>{
      if (res) { //we have a hashed password
        client.query('insert into user(mail, password) values ($1,$2)',[user.email, res])
        .then(res=>{
              client.end(); //<Remove this
              return  resolved(true);      
          })
      } else {  //crypto.hashPassword returned false, so there is an error
        client.end();
        return rejeted('error while signup');
      }
    })
    .catch(error => {
      rejeted('error while signup');
      client.end();
    });// catch
  }) //promise  
};//signup

The first time I use the signup form, it works perfectly. If I try to use it again (use the menu to get to the form, not hit back in the browser), then the form just hangs and I get no errors. If I remove the client.end() marked with <Remove this , it works perfectly.

I would really like your opinion on what am I missing here. My logic is, that if everything goes well, return true and close the client because it is no longer needed. After a successful signup, there is redirect to another page where it connects to the database with another Pool with different privileges.

Apparently there is something wrong, regarding my use of client.end();. Should promises not include it? Is it something else?

Thank you for your time

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
sehropecommented, May 29, 2018

If you use a pool you can likely avoid most of this as you never have to worry about calling client.end(). Just issue queries to the pool and deal with the results. If you can, it’s highly suggested to use a pool as it greatly simplifies things and does the right thing by default. For most non-transactional usage (i.e. most of a web request) it’s the right way to go and will be faster as well.

If you’re manually managing clients, say to add transaction management, then you’ll need to call client.end() after you’re done with the connection to shut it down. That needs to be called regardless of whether the transaction is successful or errant. Otherwise you’ll leak connections.

If I try to use it again (use the menu to get to the form, not hit back in the browser), then the form just hangs and I get no errors. If I remove the client.end() marked with <Remove this , it works perfectly.

If you created a single client manually and are reusing it across requests then calling .end() will break your app as the client can’t be reused after its closed. You should be creating the client for each request, either directly or via pool.connect(), then closing it or calling client.release() (if it’s pooled) when you’re done.

All of this is much much easier with async / await + pool.query():

const signup = async (user) => {
  const existingUser = await getUser(user.email);    
  if (existingUser) {
      return false;
  }
  // Assumes that hashPassword will reject with an error if it fails
  const hashedPassword = await crypto.hashPassword(user.password);
  const insertSql = `INSERT INTO ... /* fill in */ `;
  // Still have a race condition here if you have a UNIQUE index on email address.
  // Check out INSERT ON CONFLICT for how to deal with this (out of scope for node-postgres).
  await pool.query(insertSql, [user.email, hashedPassword]);
  return true;
}
0reactions
spimoucommented, May 29, 2018

Can I just say, there are 3 different connections to the db, each one has different db privileges (front end user only selects, signup user selects and inserts on the user table and cms user selects, updates, inserts and . deletes on certain tables) . This is considered an extra security measure that , surprisingly, is not discussed very often.

@sehrope Thanks for the help, I understand a lot of things now, and my code makes more sense. In my cms I will use transactions, so I have to use Clients and you end up helping me a lot with your remarks.

Now, the structure is

const crypto = require('./crypto.js');
const {Client} = require('pg');

const signup =  (user) => {
  const client = new Client({....});
  client.connect();
  return new Promise((resolved, rejeted)=>{
    getUser(user.email, client)
    .then(check result)
    .then(hash)
    .then(res=>{
        return client.query(...)
    })
    .then(res=>{
      resolved(true);
      client.end();
    })
    .catch(...);
  }) 
};

const getUser = (mail, client) => {
  return new Promise((resolved, rejeted)=>{
    client.query('........
}
exports.signup = signup;

Thank you for your time

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using promises - JavaScript - MDN Web Docs
A good rule of thumb is to always either return or terminate promise chains, and as soon as you get a new promise,...
Read more >
when to disconnect and when to end a pg client or pool
First, from the pg documentation*: const { Pool } = require('pg') const pool = new Pool() // the pool with emit an error...
Read more >
Promises chaining
Promises provide a couple of recipes to do that. In this chapter we cover promise chaining. It looks like this: new Promise(function(resolve ...
Read more >
Guide to promises in Node.js
When a promise is completed, it ends in either the resolved state or the rejected state. The resolved state indicates that the promise...
Read more >
Understanding the Event Loop, Callbacks, Promises, and ...
You can initialize a promise with the new Promise syntax, and you must initialize it with a function. The function that gets passed...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found