1

There is a server, that I have an access to, but do not have ownership on. It serves a node js / express application on a default port 3000. There are several scripts, that are usually run either manually from the terminal or by cron job. What I want to do is to have a button on the client-side and make an ajax request to a certain route and execute a node js command with inline arguments. For example:

node script.js 123

All routes are set and working. I have a CliController file that handles requests and has to run the command above. Currently I am using the following code:

cp.exec(`node script.js ${ip}`, function (err, stdout, stderr) {
      if (err) {
         console.log(err);
      }
      console.log(stdout);
      console.log(stderr);
 });

The script.js file is in root folder of the project, but the project itself was built by using express-generator and is being served using node bin/www command. There is a service/process on the server that runs nodemon to restart this project if it fails as well. Therefore I do not have access to output of that particular process.

If I run the command above in the terminal (from the root folder of the project, to be precise), it works fine and I see the output of the script. But if I press the button on the webpage to make a request, I am pretty sure that the script does not execute, because it has to make an update to database and I do not see any changes. I also tried to use child_process.spawn and child_process.fork and failed to get it working.

I also tried to kill nodemon and quickly start the project again to the see console output. If I do this, everything works.

What am I doing wrong ?

AhmCho
  • 380
  • 4
  • 12
  • Well, you said it all: you don't have access to the server. You won't be able to run any kind of shell command from an api call. Or if you find a way, this would mean the server is dangerously open to remote shell attacks. – NVRM Aug 22 '21 at 13:15
  • @NVRM But I can connect to server using SSH as root and I am able to run node commands in the terminal. Is it not enough? – AhmCho Aug 22 '21 at 13:26
  • Alright, then yes you will find a way. I misunderstood. Maybe simply add `&` at the end of your command, to detach the execution. Try `node script.js ${ip} &`, see what it does. See https://stackoverflow.com/questions/13338870/what-does-at-the-end-of-a-linux-command-mean – NVRM Aug 22 '21 at 13:55
  • 1
    Thank you so much, @NVRM , it worked! I previously searched for child processes in docs, but did not know about detaching. Also, wanted to upvote your comment, but for some reason I do not see the option to upvote the comment yet. Is it possible for you to answer this question so I can accept it as the answer? If it's not possible, I will answer myself, but will quote your comment. – AhmCho Aug 22 '21 at 14:31
  • 1
    Made that. See https://stackoverflow.com/help/privileges for infos about points – NVRM Aug 22 '21 at 16:53

1 Answers1

1

The process invoked may be in a blocking state, hence the parent script is simply waiting for the children process to terminate, or return something.

We can avoid this behaviour right into the shell command, by adding & (ampersand control operator) at the end.

This makes a command running in the background. (Notice, you can still control the children(s) process using the PID's and POSIX signals, this is another subject, but very related and you might find it very handy pretty soon).

Also notice that killing/stopping the parent script will also kill the children(s). This can be avoided using nohup.

This is not linked to JavaScript or node.js, but to bash, and can be used with anything in the shell.

cp.exec(`node script.js ${ip} &`, function (err, stdout, stderr) {
      if (err) {
         console.log(err);
      }
      console.log(stdout);
      console.log(stderr);
 });

Bash reference manual

NVRM
  • 11,480
  • 1
  • 88
  • 87