1

I'm using NodeJs execFile() to start a daemon process. I've wrapped the callback in a promise to use it asynchronously in other parts of my application.

I understand callbacks emit err/result upon completion. So when the daemon process fails, the promise rejects the error correctly.

Problem: when the daemon process starts correctly, the promise doesn't resolve anything, since the callback has not completed yet.

The response is received once the daemon process is stopped since that is the end of the callback lifecycle. But that's too late.

Question: How do I track the life cycle of the callback to let the promise resolve(callback_in_progress)?

Do I need to use a node event module to create event listener?

These are 2 methods from the module. The first works well, but the second is where I'm having a problem.

const { execFile } = require('child_process');
const path = require('path');
const binaryPath = require('./BinaryPaths')

const mcUtil = path.join(binaryPath, 'multichain-util');
const mcd = path.join(binaryPath, 'multichaind');

module.exports = {
    createChain: (chainName) => {
        return new Promise((resolve, reject) => {
            execFile(mcUtil, ['create', chainName], (err, res) => {
               err ? reject(err) : resolve(res);
            });
        });
    },
    startMultichain: (chainName) => {
        return new Promise((resolve, reject) => {
           execFile(mcd, [chainName, 'daemon'], (err, res) => {
              err ? reject(err.message) : resolve(res);
           });
        });
     },
};
UtkarshPramodGupta
  • 7,486
  • 7
  • 30
  • 54
  • can u show us ur code plz – sayalok Oct 09 '19 at 04:24
  • Sorry...my first time to post here. – Roscoe van der Boom Oct 09 '19 at 07:17
  • The binary files I'm using can be found here https://www.multichain.com/download-community/ – Roscoe van der Boom Oct 09 '19 at 08:14
  • @UtkarshPramodGupta Thanks for you solution. Sorry I haven't replied. I'm still trying to wrap my head around it....and other work. I'm guessing "executor" refers to the inner promise ? Or does "executor" refer to the execFile callback ? – Roscoe van der Boom Oct 16 '19 at 03:51
  • You don't need to worry about what is executor. Just use StatefulPromise class as native Promise class you have in Javascript with one more property called `state` in addition to `then()`, `catch()` or what have you. But still if you are curious, you can read more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#Syntax – UtkarshPramodGupta Oct 16 '19 at 07:13
  • I have found the answer to my problem in another thread https://stackoverflow.com/questions/27893565/get-execfile-stdout-on-chunks – Roscoe van der Boom Oct 21 '19 at 00:41

2 Answers2

1

You can create a wrapper around your Promise to get state of your promise synchronously in your code, like so:

class StatefulPromise extends Promise {
  constructor (executor) {
    super((resolve, reject) => executor(
      (val) => {
        resolve(val)
        this._state = 'Resolved'
      },
      (err) => {
        reject(err)
        this._state = 'Rejected'
      },
    ))
    this._state = 'Processing'
  }

  get state () {
    return this._state
  }
}
 
// Create a promise that resolves after 3 sec 
var myStatefulPromise = new StatefulPromise((resolve, reject) => {
  setTimeout(() => resolve(), 3000)
})

// Log the state of above promise every 500ms
setInterval(() => console.log(myStatefulPromise.state), 500)
UtkarshPramodGupta
  • 7,486
  • 7
  • 30
  • 54
0

After searching more, I have found the solution to my problem posted in anouther thread. It was quite simple. I only needed to use spawn() instead of execFile(). This will stream data instead of only resolving once the callback is done.

Solution thread here: get execFile stdOut on chunks