3

I need to run two shell commands, one-by-one. These commands are wrapped in to functions:

function myFucn1() { exec('some command', (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); throw error; } console.log(`stdout: ${stdout}`); console.error(`stderr: ${stderr}`); }); } 

and

function myFucn2() { exec('some command 2', (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); throw error; } console.log(`stdout: ${stdout}`); console.error(`stderr: ${stderr}`); }); } 

When I am calling them on my trigger function:

app.get('/my_end_point', (req, res) => { try { myFucn1(); myFucn2(); res.send('Hello World, from express'); } catch (err) { res.send(err); } }); 

it runs both commands in random order and output stdout, stderr displays only from second functions.

3
  • make myFucn1(); return something, and execute myFucn2 with an if. Commented Dec 18, 2019 at 14:12
  • 1
    Never Ever make your node behaviour synchronous. Always try to go natural way. Otherwise performance could be worst. Commented Dec 18, 2019 at 15:05
  • for the above purpose use websockets then you don't have to worry about request timeout. You can easily run async functions and get results at correct time. Commented Dec 18, 2019 at 15:13

3 Answers 3

3

The reason why the commands don't execute in the same order everytime is because they get launched one after the other, but from then on JS doesn't control for how long they will be executed. So, for a program like yours that is basically this:

launch cmd1, then do callback1 launch cmd2, then do callback2 respond to the client 

you don't have any control over when will callback1 and callback2 will get executed. According to your description, you are facing this one:

launch cmd1 launch cmd2 respond to the client callback2 (something else happens in your program) callback1 

and that's why you only see what you see.


So, let's try to force their order of execution! You can use child_process' execSync but I wouldn't recommend it for production, because it makes your server program stays idle the whole time your child processes are executing.

However you can have a very similar syntax by using async/await and turning exec into an async function:

const { exec: execWithCallback } = require('child_process'); const { promisify } = require('util'); const exec = promisify(execWithCallback); async function myFunc1() { try { const {stdout, stderr} = await exec('command 1'); } catch(error) { console.error(`exec error: ${error}`); throw error; } } // same for myFunc2 

and for your server:

app.get('/my_end_point', async (req, res) => { try { await myFunc1(); await myFunc2(); res.send('Hello World, from express'); } catch (error) { res.send(error); } }); 
Sign up to request clarification or add additional context in comments.

3 Comments

myFunc1 and myFunc2 aren't depending on each other, so this solution is just not satisfying. The correct solution would be to promesify both the functions and then use Promise.all
So await Promise.all(myFunc1(), myFunc2());
@CristianTraìna that's only in the particular case where the commands don't need to be ran in order though
1

You can use execSync instead of exec to execute your commands synchronously.

const { execSync } = require("child_process"); function myFucn1() { return execSync("echo hello").toString(); } function myFucn2() { return execSync("echo world").toString(); } myFucn1(); myFucn2(); 

2 Comments

It's simple and it can work, but this is discouraged when trying to be performant, because it blocks the event loop the whole time the child process is executing
I agree and concede that your answer is better 😀
0

It's due to nature of Javascript callback functions. Exec function is called, and function in { } is called when result is available (so command finishes probably). Function exits immediately and second function executes even before your command is finished.

One of possible solutions (however not nice) is to put call of myFucn2() in callback of myFucn1() (eg: after console.error).

Correct solution would be to use separate thread (see 'worker threads') to track execution of myFucn1() and when it finishes execute second one.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.