Gammer
Gammer

Reputation: 5628

Node: Wait for python script to run

I have the following code. Where i upload the file first and then i read the file and console the output like console.log(obj). But the response comes first and the python scripts runs behind the scene. How can i make code to wait for the python script to run then proceed?

router.post(`${basePath}/file`, (req, res) => {

    //Upload file first

    PythonShell.run('calculations.py', { scriptPath: '/Path/to/python/script' }, function (err) {
        console.log(err);
        let obj = fs.readFileSync('Path/to/file', 'utf8');
        console.log(obj);
    });

    return res.status(200).send({
        message : 'Success',
    });
});

I cannot get console.log(obj); output because it runs after the response. How can i make it wait for the python script to run and get console.log(obj) output on console.

Upvotes: 4

Views: 3575

Answers (1)

dhilt
dhilt

Reputation: 20784

To return the result after some async operation, you should call res.send inside the done-callback.

router.post(`${basePath}/file`, (req, res) => {

    //Upload file first

    PythonShell.run('calculations.py', { scriptPath: '/Path/to/python/script' }, function (err) {
        console.log('The script work has been finished.'); // (*)
        if(err) {
          res.status(500).send({
            error: err,
          });
          console.log(err);
          return;
        }
        let obj = fs.readFileSync('Path/to/file', 'utf8');
        console.log(obj); // (**)
        res.status(200).send({
            message : 'Success',
        });
    });
});

Then if you will not see the log (*) in the console, then it would mean that the script does not work or works improperly. The callback is not being called. First of all, you need to be sure that the script (PythonShell.run) works and the callback is being called. The POST handler will wait until you call res.send (with no matter of delay value), so that callback is the main point.

Also readFileSync could fail. In case of readFileSync failure you should see an exception. If it's ok then you'll see the next log (**) and the response will be sent.


I see PythonShell in your code. I have no experience with it, but after some reading I think that the problem could be in how you are using it. It seems the python-shell npm package, so following it's documentation you may try to to instantiate a python shell for your script and then to use listeners:

let pyshell = new PythonShell('calculations.py');

router.post(`${basePath}/file`, (req, res) => {
  pyshell.send(settings); // path, args etc
  pyshell.end(function (err) {
    console.log('The script work has been finished.');
    if(err) { res.status(200).send({ error: err }); }
    else { res.status(200).send({ message : 'Success' }); }
  });
});

This approach could be more appropriate because the pyton shell is kept open between different POST requests. This depends on your needs. But I guess it does not solve the problem of script running. If you are sure that the script itself is fine, then you need just to run it properly in the Node environment. There are some points:

  • path to script
  • arguments
  • other settings

Try to remove all arguments (create some new test script), cleanup settings object (keep only path) and execute it from Node. Handle its result in Node. You should be able to run the simplest script by correct path! Research how to setup correct scriptPath. Then add an argument to your script and run it with an argument. Hanlde the result again. There are not so many options, but each of them could be the cause of improper call.

Upvotes: 5

Related Questions