0

I can't figure out why this app keeps running. I've tried using the why-is-node-running package but I'm not perfectly sure how to read the output properly. Here's the first output of it:

There are 30 handle(s) keeping the process running
    # TCPWRAP
    /node_modules/mongodb/lib/core/connection/connect.js:269 - socket = tls.connect(parseSslOptions(family, options));
    /node_modules/mongodb/lib/core/connection/connect.js:29  - makeConnection(family, options, cancellationToken, (err, socket) => {
    /node_modules/mongodb/lib/core/sdam/monitor.js:182       - connect(monitor.connectOptions, monitor[kCancellationToken], (err, conn) => {
    /node_modules/mongodb/lib/core/sdam/monitor.js:206       - checkServer(monitor, e0 => {
    /node_modules/mongodb/lib/core/sdam/monitor.js:92        - monitorServer(this); 

My guess is it has something to do with MongoDB not closing properly. Although, when I removed all of the other functions between opening the client and closing it, it opened and closed perfectly.

Adding process.exit() at the end closes program properly, but I'd like to figure out why it isn't closing.

A summary of the app is that it is getting data from MongoDB, cleaning it, and then writing it into Firestore - so a lot of async actions going on, but I didn't see Firestore-related stuff pop up in the why-is-node-running logs.

const GrabStuffFromDBToCalculate = require("./helpers/GrabStuffFromDBToCalculate");
const SendToFirestore = require("./helpers/SendToFirestore");
const log = require("why-is-node-running");
const { MongoClient } = require("mongodb");
require("dotenv").config();

const main = async () => {
  try {
    const client = await MongoClient.connect(process.env.MONGODB_URI, {
      useNewUrlParser: true,
      useUnifiedTopology: true
    });
    const collection = await client.db("test").collection("testcollection");
    const trip_object = await GrabStuffFromDBToCalculate(collection);
    SendToFirestore(trip_object);
    client.close();
    log(); // "There are 30 handle(s) keeping the process running including node_modules/mongodb/lib/core/connection/connect.js:269 - socket = tls.connect(parseSslOptions(family, options));"
    // process.exit() // this closes everything but I'd rather not have to use this
  } catch (err) {
    console.log(err);
    client.close();
  }
};

const runAsync = async () => {
  await main(); // this exists because I'm usually running multiple main() functions
};

runAsync();

SendToFirestore code:

const firebase = require("firebase");
const firebaseConfig = require("../config");

module.exports = SendToFirestore = trip_object => {
  if (!firebase.apps.length) {
    firebase.initializeApp(firebaseConfig);
  }
  const db = firebase.firestore();
  db.doc(`hello/${object._id}`).set({
    objectid:object._id
  });
};

GrabStuffFromDBToCalculate code (way simplified):

module.exports = GrabStuffFromDBToCalculate = async collection => {
  const cursor = await collection
    .aggregate([

        // does a bunch of stuff here

    ])
    .toArray();
  const newObj = cursor[0];
  return newObj;
};
mpc75
  • 937
  • 9
  • 22
  • 2
    It seems like there more to see such as the code for `SendToFirestore()` and `GrabStuffFromDBToCalculate()`. Also, you should call `log()` AFTER you `await client.close()` so you're sure that is complete before `log()` lists the open handles. – jfriend00 Feb 04 '20 at 01:09
  • You could try forcing the close with `client.close(true)`. I've used it before when the mongo client has kept the process alive but I haven't taken the time to investigate why the client doesn't close without it. – cbr Feb 04 '20 at 01:10
  • 1
    Also, doesn't `log()` show you the ACTUAL handles that are still open? Can you share that output with us? – jfriend00 Feb 04 '20 at 01:10
  • 1
    Please edit the question to show the complete, minimal code that exhibits the problem. What you have is hiding too many details. https://stackoverflow.com/help/minimal-reproducible-example – Doug Stevenson Feb 04 '20 at 01:15
  • 1
    This is a small tweak and probably wont fix your problem, but you might also just want to put `client.close()` in a `finally` block instead of catch (and the main block). This guarantees it's the last thing that happens after any branch in your appliation. – Evert Feb 04 '20 at 01:19
  • 1
    Also I believe that `client` might not exist in your catch block. Define `client` outside of the try {} scope. – Evert Feb 04 '20 at 01:20
  • @jfriend00 I've just added as much as possible - had to simplify though. I added log() after and it and it outputs the same result, but thank you for the recommendation. I added a bit more from the log at the top of the post. – mpc75 Feb 04 '20 at 01:27
  • @DougStevenson I added much more, thanks. – mpc75 Feb 04 '20 at 01:28
  • @Evert Thanks for the recommendation, good to know that it's a best practice. I've now implemented it, but unfortunately, it didn't solve the problem (I defined client outside the try catch as you recommended as well). – mpc75 Feb 04 '20 at 01:30
  • @cubrr Thanks for the recommendation, I tried that but it didn't work. – mpc75 Feb 04 '20 at 01:32
  • 1
    Don't you have an open firebase connection? See [How to close firebase connection in nodejs so nodejs will exit](https://stackoverflow.com/questions/38222757/how-to-close-firebase-connection-in-node-js). Also, I'm not sure you understood that I was suggesting that you use `await` as in `await client.close()` before calling `log()` so you are sure that the client connection has been closed before you do the logging. `client.close()` is an asynchronous method so your original code would `log()` before that close was complete. – jfriend00 Feb 04 '20 at 01:35
  • @jfriend00 well done! Thank you! I am actually using firestore but your recommended concept worked and you're absolutely right, I had an open connection still. I called db.terminate() after awaiting the database sets and it closed everything down properly. – mpc75 Feb 04 '20 at 01:43

1 Answers1

0

Making my comment into an answer since it led to the missing piece.

Node does not shut down because you have an open Firestore connection. You will have to call terminate to allow the SDK to shut down and release resources:

db.terminate();

Which is relevant for allowing nodejs to shut itself down automatically.


Also, I'm not sure you understood that I was suggesting that you use await as in

await client.close()

before calling log() so you are sure that the client connection has been closed before you do the logging. client.close() is an asynchronous method so your original code would log() before that close was complete.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 1
    The OP's code is using Firestore, not Realtime Database. – Doug Stevenson Feb 04 '20 at 01:57
  • @DougStevenson true but the concept is the same: the connection was open = figure out how to close it. I think it counts as an answer although I 100% agree that putting ```db.terminate()``` would be more accurate than ```firebase.database().goOffline()``` in the answer. – mpc75 Feb 04 '20 at 01:59
  • If you're using Firestore, you should use the code in my answer. – Doug Stevenson Feb 04 '20 at 02:01
  • I would avoid marking this as correct since it might mislead someone in the future. – Doug Stevenson Feb 04 '20 at 02:02
  • @mpc75 - Updated to use terminate. – jfriend00 Feb 04 '20 at 02:07
  • It's still linking to unhelpful questions that refer to RTDB. – Doug Stevenson Feb 04 '20 at 02:08
  • @DougStevenson - That's just the article that led us to understand the issue. – jfriend00 Feb 04 '20 at 02:10
  • Pretty sure that article does not suggest that you call `db.terminate()` as the answer says. If you're wondering why I'm being persistent about this, it's because people mix up these two databases **all the time** and we don't need any more mixups. As I'm sure you discovered here. – Doug Stevenson Feb 04 '20 at 02:12
  • @DougStevenson just noticed that you're formerly of Firebase, thanks for your help and expertise as well on this one :) – mpc75 Feb 04 '20 at 02:33