1

I am trying to execute this piece of node js code which execute a python script. Through this code works fine. but the response "running" and "finished" are displayed on front end immediately. "finshed" has to be displayed once the execution of python scripts gets completed.

app.post('/execute', function(request, response){
    response.write("running");
    console.log("executing")
    var pyshell = new PythonShell('./python_codes/test.py')
    pyshell.on('message', function (message) {console.log(message);});
    pyshell.end(function (err) {if (err){throw err;};console.log('finished');});
    response.write("finished");
    response.end();
});
nishant kumar
  • 507
  • 10
  • 28
  • `PythonShell` uses `child_process.spawn`, which is asynchronous - you're saying here "Run this python thing, and tell me when it's done by using the callback I've given you with `.end`, and while you're doing that I will carry on with my own stuff". I suspect you'll need to either wait for `pyshell.terminated` to show the right value, or pass the response into the `.end` callback – Simon Fraser Apr 19 '17 at 11:13
  • @SimonFraser The full code isn't shown so it's unknown if the HTTP library supports that - it's possible (and even likely) that once the `app.post` callback is done running `response.end()` will be called implicitly. – Fredrick Brennan Apr 19 '17 at 11:22
  • 1
    @FredrickBrennan Fair point :) I'm more python than node, so I was trying to work things out looking at PythonShell – Simon Fraser Apr 19 '17 at 11:28

2 Answers2

1

It happens because the PythonShell class is asynchronous. What your code is doing is creating a PythonShell object, storing it in variable pyshell, and then adding a few events to the pyshell object. It then directly continues to write "finished".

Because writing "finished" is not part of the callback for the end() function, it happens right away. I see at least three things you can do:

  1. If the HTTP library you are using supports it, just add the response.write("finished"); response.end(); code to the pyshell.end callback.
  2. Call Python using a library which supports pausing the current execution thread (or use execSync). This is bad practice, because it defeats the purpose of using a concurrent framework like node.js, but would work.
  3. Use WebSockets (or socket.io, which works even if WebSockets aren't available, such as through CloudFlare) to transmit the "finished" message.
Community
  • 1
  • 1
Fredrick Brennan
  • 7,079
  • 2
  • 30
  • 61
1

You should add your response inside the callback function

app.post('/execute', function(request, response){

  response.setHeader('Connection', 'Transfer-Encoding'); 
  response.setHeader('Content-Type', 'text/html; charset=utf-8');

  response.write("running");
  console.log("executing")
  var pyshell = new PythonShell('./python_codes/test.py')
  pyshell.on('message', function (message) {console.log(message);});
  pyshell.end(function (err) {
    if (err){
      throw err;
    };
    console.log('finished');
    response.write("finished");
    response.end();
  });
});
Ezzat
  • 931
  • 6
  • 13
  • I tried but with approach it is also not sending the "running" msg. all the msg are sent after execution test.py – nishant kumar Apr 19 '17 at 11:53
  • Add `response.setHeader('Connection', 'Transfer-Encoding');` `response.setHeader('Content-Type', 'text/html; charset=utf-8');` To allow browser to show the content immediately. – Ezzat Apr 19 '17 at 12:21