jeff-ridgeway
jeff-ridgeway

Reputation: 171

Why is Spawn() never being called?

I have had some experience with node.js and express for quite some time, but I keep running into this bug in my code. In my service file, I am calling spawn() inside a resolved Promise in my code. Somehow my spawn code is never called (or if it is called, ls.on('close') or ls.on('error') never gets called), and I don't know why. I think I understand the asynchronous nature of Spawn(), but I guess I don't? 🤷🏾‍♂️ Here is the code below from my finalSendFiles.service.js file:

const { spawn } = require('child_process');

const finalSendFiles = async (uVal) => {

    try {
        //new code
        console.log("I'm here")
        const getfirst_username = get_username(uVal);
        getfirst_username.then(function (username_value) {
            const pyScript = "./pythonFile.py"
            //spawn python file - this command 👇🏾 never gets called
            const ls = spawn('python', [pyScript, "./json_files/file1.json", "./json_files/file2.json", `${username_value}`])
            ls.on("error", (err) => {
                console.log(err)
            });

            ls.on("close", (code) => {
                console.log("You're done with the file!");
                console.log(`child process exited with code ${code}`);
            });
        });
    } catch (error) {
        console.log(error)
    }
}

module.exports = {
    finalSendFiles
}

I would appreciate any help on a way forward!

P.S. The two files that are needed to send are written to the system using fs.writeFile(), so those files need to be done before the spawn actually executes


Update (06/01/20): I have done some testing using mocha.js and found some interesting findings. First, when I run npm test on the code below, everything is successful.

test.js

describe('spawnFunc', function() {
  describe('#spawn()', function() {
    it('it should call the python script', function(done) {
      const pyScript = "./p1.py"
      const ls = spawn('python', [pyScript])

      ls.stdout.on('data', function(data){
        console.log(data.toString());
      }).on("close", (code) => {
        console.log("You're done with the .csv file bro!");
        console.log(`child process exited with code ${code}`);
        done()
      });
    });
  });

});

The ouput of the my code is:

> mocha

  spawnFunc
    #spawn()
You've made it to the python file!

You're done with the .csv file bro!
child process exited with code false

So somehow, my testing is working. However, when I do const ls = spawn('python', ["./p1.py"]) in my regular code it never gets to the spawn. I have already tried python-shell and that is not working either. I seem to be running into this same issue here

Again any help would be appreciated!

Upvotes: 0

Views: 210

Answers (1)

jfriend00
jfriend00

Reputation: 707298

I see a couple possibilities:

  1. The promise that get_username() returns could end up rejecting. You don't have a .catch() handler to detect and handle that.

  2. Also, your finalSendFiles() function will return long before the spawn() operation is done in case that is also what is confusing you.

I figured something like that was going. Yeah I need spawn() to return first and then finalSendFiles()

Well, you can't prevent finalSendFiles() from returning before the spawn() is done (that's the nature of asynchronous logic in Javascript) unless you use spawnSync() which will block your entire process during the spawnSync() operation which is generally not something you ever want to do in a server.

If you want to retain the asynchronous version of spawn(), then you will need to return a promise from finalSendFiles() that is linked to the completion of your spawn() operation. You can do that like this:

const finalSendFiles = (uVal) => {
    console.log("I'm here")
    return get_username(uVal).then(function (username_value) {
        const pyScript = "./pythonFile.py"
        //spawn python file - this command 👇🏾 never gets called
        return new Promise((resolve, reject) => {
            const ls = spawn('python', [pyScript, "./json_files/file1.json", "./json_files/file2.json", `${username_value}`])
            ls.on("error", (err) => {
                console.log(err)
                reject(err);
            }).on("close", (code) => {
                console.log("You're done with the file!");
                console.log(`child process exited with code ${code}`);
                resolve(code);
            });
        });
    });
}

Note: your caller will have to use the promise that it returns to see both completion and errors like this:

finalSendfiles(...).then(code => {
    console.log(`Got return code ${code}`);
}).catch(err => {
    console.log(err);
});

Upvotes: 1

Related Questions