Node programs do not exit if active event listeners

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the javascript category.

Last Updated: 2024-04-24

I had a nodejs process that connected to a MySQL database, ran a query, and printed some results. Then it just hung without exiting.

What was up? Here's the code:

let migrationDb = mysql.createConnection({
  host: mysqlDbHost,
  user: mysqlDbUsername,
  password: mysqlDbPassword,
  database: mysqlDbDatabase,
  charset: 'utf8mb4'
})

migrationDb.query(query, (error, result, _fields) => {
  if (error) {
    console.log("DB issue: ", error)
  } else {
    result.forEach(callback)
  }
})

The issue was that node registered a DB connection and was holding onto it still.

The solution was to close the DB connection once I was done with my query:

migrationDb.end()

// Another more general but more abrupt and risky solution:
process.exit()

Thinking about the asynchronous nature of JavaScript, why might this step be logically necessary? Well the code for running the DB query (migrationDb.query()) executes immediately and thus the end of the file will be reached nearly instantly - and before any query results were returned. Were this a more "standard" language like Python, the program would exit at this point. But JavaScript is not Python. Rather the JavaScript event loop keeps going, in order to eventually return a response once the query returns. But there's no knowing how long that will take, so the program doesn't know when to finish up. That's why we have to tell it so explicitly.

Lessons

Due to its asynchronous nature, Node programs do not exit if there are any active event listeners.