1

When I run this script from the command line (node script.js), it seems to work fine. All the activities from Firestore get printed to the console, followed by "done.". But then the script doesn't exit right away. It hangs for exactly 60 seconds, and then I get my prompt back. What's up with that?

Update: Yes, this is the whole script.

const firebase = require('firebase')

const config = {
  apiKey: 'AIzaSyBmauMItX-bkUO1GGO_Nvrycy1Y6Pj1o_s',
  authDomain: 'fir-test-app-501b1.firebaseapp.com',
  databaseURL: 'https://fir-test-app-501b1.firebaseio.com',
  projectId: 'fir-test-app-501b1',
}

firebase.initializeApp(config)
firebase.firestore().collection('activities')
  .get()
  .then(qs => qs.docs.forEach(doc => console.log(doc.data())))
  .then(() => console.log('done.'))

I am using Node v8.11.3 and Firebase v5.11.1. GitHub link: https://github.com/danbockapps/firebase60

Dan B.
  • 1,451
  • 2
  • 14
  • 23
  • Have you tried debugging the code in an IDE to see where it's hanging out? Rather than us guessing or you waiting for an answer from someone here, that might be your best route for now – abelito May 26 '19 at 14:30
  • 2
    Is this really the entire script? – Itay Moav -Malimovka May 26 '19 at 14:31
  • @abelito What would you do with a debugger? Set a breakpoint somewhere? – Dan B. May 26 '19 at 14:34
  • @ItayMoav-Malimovka I have hidden all the boilerplate setup stuff in FirebaseConfig.js and referenced it in the first line. – Dan B. May 26 '19 at 14:36
  • @DanB. I would break out the code into separate named functions and add a breakpoint inside that last console.log('done.'), then step from there -- Step through, then out and see where the app is hanging. If that thread finishes, then there must be some other thread still alive that is keeping the app running – abelito May 26 '19 at 14:42
  • @ItayMoav-Malimovka But yes, it's the entire script. I reduced it down to the minimum to make it easy for you all to read! – Dan B. May 26 '19 at 14:50
  • Pretty sure firebase uses some sort of connection pool and keeps the connection open until some timeout (1min seems reasonable). Node.js won't terminate with a connection still open. – Bergi May 26 '19 at 14:50
  • @abelito I put a breakpoint on `console.log('done.')` and then pressed the Step Out button about a hundred times. It jumps between async_hooks.js, inspector_async_hook.js, and a bunch of other files. There was a delay between two of the step outs (the processImmediate function in timers.js and the emitHookFactory function in async_hooks.js) but I'm not sure what to do with this information. – Dan B. May 26 '19 at 14:56
  • @DanB. I've created a Firebase project + Firestore collection, authenticated using a custom account, created a local node project that uses firebase-admin to connect to the database, required a separate js file, destructured that exported object to get the database, and run exactly your code from command line, and my code immediately exits after the done call. The issue must either be on the Firebase side or in some other piece of code you don't have up. Can you give us a bit more to go on? – abelito May 26 '19 at 15:24
  • 1
    @abelito I simplified and pushed the whole thing to GitHub: https://github.com/danbockapps/firebase60 – Dan B. May 26 '19 at 15:59
  • 1
    I'm able to reproduce this issue with your exact version of node, firebase, and your code. Hopefully I'll have an answer in a few minutes for you – abelito May 26 '19 at 16:15

1 Answers1

2

Here you go:

var firebaseApp = firebase.initializeApp(config);
var database = firebase.firestore();

database.collection('activities')
  .get()
  .then(qs => qs.docs.forEach(doc => console.log(doc.data())))
  .then(() => {
      console.log('done.');
      firebaseApp.delete();
      // database.disableNetwork(); // Another way to do this, though not as clean
  });

Managed to dig into the code of the .get() call on the collection and see that there is a 60 second timeout in AsyncQueue that lives after everything is done. Figured there must be a disconnect switch somewhere that shortcircuits the inner timers that that google library runs on and found it in firebaseApp.delete() which does the following according to its docs:

(method) firebase.app.App.delete(): Promise

Renders this app unusable and frees the resources of all associated services.

This works for 5.11.1 as well as 6.0.4, I highly recommend upgrading now while you're early in the project. I was using the npm package firebase-admin instead of firebase like you're using and did NOT need to make this call to free resources.

Community
  • 1
  • 1
abelito
  • 1,094
  • 1
  • 7
  • 18
  • Thanks. It's become clear in reading I've done since posting the question that firebase-admin is probably the best tool for this job, rather than regular Firebase JavaScript. – Dan B. May 26 '19 at 18:12
  • Right, and I use it primarily because there are admin funcs that I use in many of my apps that require it https://stackoverflow.com/questions/42958776/whats-the-difference-between-the-firebase-and-the-firebase-admin-npm-module Best of luck to you in the future, and in your development! – abelito May 26 '19 at 18:22