0

I'm creating a promise based API. Everything works fine if I make one request at a time, but, if 2 or more requests hit the server within a second of each other, I get the following error

Error: Cannot enqueue Quit after invoking quit

The odd thing is, I get a valid and correct results returned to API requests, but, clearly something is wrong.

I've created a small project on gitHub. You can check it out, I've created an SQL seeder with 2 users so you can just copy paste the query into your database (the seeder even creates a new database)

The project is small, just put your database credentials in the the configs/mysql.js file, then run the file node multiple_sends.js

You'll see that the correct answer is returned, but node blows errors.

I don't think the error is in the mysql module. The reason is, if I take the code from my model and create a CLI script, no errors are returned, mysql doesn't issue any warnings

// models/user.js
let mysql     = require('mysql');

let configs   = {
  host     : '127.0.0.1',
  user     : 'root',
  password : 'something',
  database : 'demo'
}

/**
 * This constructor function is responsible for running queries against
 * the mysql database
 */
function Users()
{
  // These are PRIVATE variables, they can only be accessed within this class
  let mysql_connection = null;

  this.getUserByEmail = function(email)
  {
    let parent = this;

    mysql_connection = mysql.createConnection(configs);

    return this.mysqlConnect()
      .then((connectionId) =>
      {
        console.log(`getUserByEmail: connection id: ${connectionId}`);

        let sql = 'SELECT user_id, first_name, last_name, upassword, email, '
          + 'birthday, roles FROM users WHERE email = ?';

        return parent.runQuery(sql, [email]);
      })
      .then((results) =>
      {
        if (results.resultSet.length === 0) {
          return null;
        }

        let resultSet = results.resultSet[0];

        // return our result to the calling method.
        return (resultSet);
      })
      .catch(error => {
        throw error;
      })
  }

  /**
   * Run this method when trying to connect to the database
   * @param Object error
   * @return Promise
   */
  this.mysqlConnect = function()
  {
    return new Promise(function(resolve, reject)
    {
      mysql_connection.connect(function(error)
      {
        if (error) {
          console.log('Error making connection', error);

          throw "Failed connection to database";
        }

        // we don't have to return anything, this is just to show that Promises
        // can return
        resolve(mysql_connection.threadId);
      });
    });
  }

  /**
   * use this method for running selects
   * @param string query - well formed query
   * @return Promise
   */
  this.runQuery = function(query, params)
  {
    return new Promise(function(resolve, reject)
    {
      mysql_connection.query(query, params, function(error, results, fields)
      {
        mysql_connection.end((err) => {
          if (err) {
            console.log('error terminating connection: ', mysql_connection.threadId);
            console.log('error ', err);
          }
        });

        if (error) {
          reject(error);
        }
        resolve({resultSet: results, fieldSet: fields});
      });

    });
  }
}

module.exports =  Users;

Here is script which calls the model

//main.js
let Users = require ('./models/user');

function getUser1Info()
{
  user1.getUserByEmail('original.logger@example.com')
    .then(userData1 => {
      let ctime = new Date();
      console.log(ctime.getTime(), 'user data: ', userData1.user_id)
    })
    .catch((error) => {
      console.log('error!', error);
    });
}


function getUser2Info()
{
  user2.getUserByEmail('billy.b.parker@example.com')
    .then(userData2 => {
      let ctime = new Date();
      console.log(ctime.getTime(), 'user data: ', userData2.user_id)
    })
    .catch((error) => {
      console.log('error!', error);
    });
}

let user1 = new Users();
let user2 = new Users();

setTimeout(() => {
  getUser1Info();
}, 1000);

setTimeout(() => {
  getUser2Info();
}, 999);

This code un-modified from the models/user.js in my API. This leads me to believe that the way I'm creating models in Express is fundamentally broken.

Any help is appreciated

Kearney Taaffe
  • 647
  • 8
  • 20

1 Answers1

0

If you using the node-mysql module, just remove the .connect and .end. Just solved the problem myself. Apparently they pushed in unnecessary code in their last iteration that is also bugged. You don't need to connect if you have already ran the createConnection call

Cannot enqueue Handshake after invoking quit

What i would also do: Use Knex instead of plain mysql

Tobias Lins
  • 2,543
  • 19
  • 22
  • I don't think so. I just took the code from my model and created a simple script which calls the model twice, simultaneously. See above edit. This should mimic multiple HTTP requests for information. There is no problem with the way the code is written: .connect() -> query() -> end() – Kearney Taaffe Jan 19 '18 at 16:54