20

My script performs some asynchronous tasks using promises (with the q library). Running mocha tests works fine. However running the script from the command line does not. The node process immediately dies.

var bot = require('./bot');

bot.getCategories().then(function (categories) {
  console.log('Found ' + categories.length + ' categories');
});
Kees de Kooter
  • 7,078
  • 5
  • 38
  • 45
  • 1
    What is `./bot`, what does it do? Does your script die as well when your replace `bot.getCategories()` with `Q.resolve()`? – Bergi Sep 15 '15 at 14:41

3 Answers3

13

Node.js will exit when there are no more callbacks to process. You can use setInterval or setTimeout to always keep one so that the process does not automatically exit.

function wait () {
   if (!EXITCONDITION)
        setTimeout(wait, 1000);
};
wait();
Hyo Byun
  • 1,196
  • 9
  • 18
12

My script performs some asynchronous tasks using promises (with the q library). Running mocha tests works fine. However running the script from the command line does not. The node process immediately dies.

This is most certainly a bug, please do report it. The Node.js environment should not exit prematurely while there are things still queued in the event loop.

You should not have to alter your code one bit for this to happen. The Q library (keep in mind there are more modern and native alternatives today) schedules async callbacks on the process.nextTick "microtask" queue. Your bot library presumably also performs IO, both these things should cause node not to terminate.

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • I'd rather expect a bug in `bot.getCategories()`, not in node. Maybe the promise is never resolved, then Q doesn't schedule a microtask either. – Bergi Sep 15 '15 at 14:42
  • @Bergi unless `bot.getCategories` references a native module then any bug it has is _still_ a node bug since Node should be aware of all pending io events. If it is a native module then it might be a bug there (however, most people use very few native modules). These fact these sort of bugs in Node aren't very rare also adds to my suspicion (they do get handled fast though). – Benjamin Gruenbaum Sep 15 '15 at 14:44
  • They are not? OK, I did suspect a library mistake was more likely - especially if we didn't see the code or know what it does (and whether there is actually IO involved). – Bergi Sep 15 '15 at 14:48
  • The `bot` is pulling data from the web, would that count as IO? – Kees de Kooter Sep 15 '15 at 20:10
4

Let's start like this:

'use strict'

const timeoutPromise = (time) => {
    return new Promise((resolve, reject) => { setTimeout(() =>
        { console.log('howdy'); resolve('done') }, time) })
}

below we do...

Ending A) - simple promise

console.log('start')
timeoutPromise(1000)
console.log('end')

start and end will appear immediately. it will take another second to see 'howdy' and get our terminal prompt back. (so in that sense the main script is kept alive, but presumably not what the OP wants...)

Ending B) - waiting for promise return

console.log('start')
return timeoutPromise(1000)
console.log('end')

start will appear, after 1 second 'howdy' will appear. 'end' is unreachable. So here we truly wait for the promises and could do things with them…

Ending C) - then()

console.log('start')
return timeoutPromise(1000).then((result) => {
        console.log('end', result)
        process.exit(123)  // usually 0 for 'ok', just demo!
    }
)

start will appear, one seconds goes by and 'howdy', 'end' and 'done' appears. And could be used to send a return value.

$>node haveMainWait.js
  start
  howdy
  end done

$>echo $?    // return value of last command
  123

Almost certainly you want a .catch() after the .then() in case the promise gets rejected... (and returning a nonzero exit code only in that case)

Instead of a single Promise like timeoutPromises(…) you could of course use Promise.all(…) or an async/await-Function (which has to be wrapped back to promises somewhere on the hierarchical way up... you have that covered here, too).

Frank N
  • 9,625
  • 4
  • 80
  • 110