Terminate a process from node js - node.js

//Run commands to start navigation and robot_pose package
nav = spawn("roslaunch",["turtlebot3_navigation", "turtlebot3_navigation.launch","map_file:=$HOME/catkin_ws/src/robot-rosbridge/server/newmap.yaml"], { shell: true })
nav.stdout.on("data", data => {
console.log(`stdout: ${data}`);
});
nav.on('error', (error) => {
console.log(`error: ${error.message}`);
res.sendStatus(500)
});
Well here I'm trying to terminate the nav process using "nav.kill()" but the process is not terminating .Earlier while I was using spawn without { shell: true } nav.kill() worked fine but now its not working.
On the whole I'm trying to spawn a process when a specific route is requested and terminate it when another route is requested
i.e.,
const express = require('express')
const app = express()
app.get("/start", (req, res) => {
//spawn a process
});
app.get("/stop", (req, res) => {
//kill process
});
I'm confused as to how spawn is working. Can anyone suggest a solution and the working of the spawn function or any better alternative.
Thanks in advance.

Related

exec function in Angular

I am trying to run a bash command through Angular.
After some research i found the code below that should be working
import { ChildProcess, exec } from 'child_process';
#Injectable({
providedIn: 'root'
})
export class CommandService {
runCommand(command: string): Promise<string> {
return new Promise((resolve, reject) => {
exec(command, (error: Error, stdout: string, stderr: string) => {
if (error) {
reject(error);
}
resolve(stdout);
});
});
}
}
then i call it in my .ts file
import { CommandService } from './command.service';
export class YourComponent {
output: string;
constructor(private commandService: CommandService) {}
run() {
this.commandService.runCommand('ls -la')
.then(output => this.output = output)
.catch(error => console.log(error));
}
The problem is that even though there doesnt seem to have any errors, when i try to run it it says:
error TS2307: Cannot find module 'child_process' or its corresponding type declarations.
3 import { ChildProcess } from "child_process";
, even though i can see that the file exists in my project.
Is there something i can do to fix that ? If not can i run a command some other way through Angular ?
Thanks in advance
I afraid you can't do that dave Jason.
child_process is available in a nodeJS runtime and Angular runs in a browser. That's 2 different runtimes which only have in common to use JS as a language.
Also, don't expect to be able to run a bash command from the browser that would be a MASSIVE security issue.
Matthieu Riegler is right, you cannot access OS features from within the browser environment. That being said, depending on what you want to do, you could have the bash command run at build time (e.g. with an npm script) or if you really need it at run time and happen to have a backend as well, you could expose an endpoint that runs the bash command on demand and return the result over http.
For anyone who might come to this question for answers:
it's better to use Nodejs (backend) for bash commands.
an example of what i was trying to do is shown in the code below :
onst express = require("express");
const { exec, execSync } = require("child_process");
const cors = require("cors");
const path = require("path");
const app = express();
app.use(
cors({
origin: "http://localhost:4200",
})
);
app.get("/ls", (req, res) => {
exec("ls -la .", (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return res.status(500).send({ error });
}
res.send({ output: stdout });
});
});
const homeDirectory = execSync("echo ~").toString().trim();
const frontendPath = path.join(homeDirectory, "frontend-software");
process.chdir(frontendPath);
exec("ng serve --open", (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log(stdout);
});
The 1st exec is an ls call and the 2nd is to run an angular project.
Hope it helps you all!

nodejs: Start server and look for string "server started at 127.0.0.1:8000" and then start the tests

I am starting the server from my NodeJS script and then want to execute my tests. But when I start the server the server start process doesn't return as it is running and control is not returned back. The server starts and the app can be accessed on http://localhost:8000.
trying to start the server and then monitor the stdout of the runserver process and look for a match "Starting server at 127.0.0.1:8000" and then proceed to run the tests.
Is there any way it can be done using exec or spawn node command and then monitor for the required string to start my tests ?
Based on previous question here where starting test on polling when Http://localhost:8000 is up and running.
Solution I am looking for is Starting test based on stdout data string matches - "Starting development server".
Yes, use spawn and look for the string, then run your tests, monitor SIGTERM and SIGINT, then pass it along to the child.
const {
spawn
} = require('child_process')
// your cmd to start the server, possibly spawn('python', ['manage.py', 'startserver'])
const server = spawn('node', ['server.js'])
let timer = null
server.stdout.on('data', (data) => {
console.log(`stdout: ${data}`)
// look for the string in stdout
if (data.includes('Starting development server')) {
console.log('Commencing tests in 2 seconds')
timer = setTimeout(() => {
console.log('Run tests')
// ...
// tests complete
setTimeout(() => {
console.log('Tests completed, shutting down server')
server.kill('SIGINT')
}, 2000)
}, 2000)
}
})
server.stderr.on('data', (data) => {
clearTimeout(timer)
console.error(`stderr: ${data}`)
});
server.on('close', (code) => {
clearTimeout(timer)
console.log(`child process exited with code ${code}`);
});
process
.on('SIGTERM', shutdown('SIGTERM'))
.on('SIGINT', shutdown('SIGINT'))
.on('uncaughtException', shutdown('uncaughtException'))
function shutdown(signal) {
return (err) => {
console.log(`\n${signal} signal received.`)
if (err && err !== signal) console.error(err.stack || err)
console.log('Killing child process.')
server.kill(signal)
}
}
Result
node spawn.js
stdout: Starting development server http://localhost:8000
Commencing tests in 2 seconds
Run tests
Tests completed, shutting down server
stdout:
SIGINT signal received.
stdout: Closing HTTP server.
stdout: HTTP server closed.
child process exited with code 0
The test server script used was the following, note above that it's passing back the SIGINT signal it received.
const express = require('express')
const app = express()
const port = 8000
app.get('/', (req, res) => res.send('Hello World!'))
const server = app.listen(port, () => console.log(`Starting development server http://localhost:${port}`))
process
.on('SIGTERM', shutdown('SIGTERM'))
.on('SIGINT', shutdown('SIGINT'))
.on('uncaughtException', shutdown('uncaughtException'))
function shutdown(signal) {
return (err) => {
console.log(`\n${signal} signal received.`)
if (err && err !== signal) console.error(err.stack || err)
console.log('Closing HTTP server.')
server.close(() => {
console.log('HTTP server closed.')
//
process.exit(err && err !== signal ? 1 : 0)
})
}
}

Node and talking to child processes

Context
Writing a serial monitor to listen to an Arduino isn't hard. Starting it with command line params for port name and baudrate is straightforward, and thus it's not complicated to configure and launch the monitor from Node:
child_process.exec("./monitor COM6 115200");
This question concerns exec, fork and spawn which are similar but with subtleties I do not yet grasp. As well as launch with parameters, I need to
Capture the output so I can display it in a window
Kill the child process
to re-launch with different parameters
to flash the Arduino and then re-launch after it reboots
I used netcore to write a console app that takes two command line arguments, then connects and listens, echoing to its stdout. I chose netcore because it can run on all three platforms.
Questions
Which should I use of exec, fork and spawn?
How do I kill the child process?
How do I capture the stdout of the child process?
Node documentation talks about a kill method on a subprocess object. The sample code on that page implies this object is returned by spawn but when I use spawn it seems to fail silently. That or it's working but I don't know what I'm doing, which is why I'm posing this question.
All of this Node code will be part of a VSCode extension, so if you also know about those I'd like to pipe stdout to a VSCode OutputChannel if that's possible.
With spawn your are able to listen to stdout.
and then kill process with kill()
From official NodeJS docs:
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
// some logic
ls.kill()
EDIT: a more specific example:
// server.js --------------
const http = require('http');
const server = http.createServer(
(function() {
console.log('Initializing server');
return (req, res) => {
res.end('Hello World');
};
})()
);
server.listen(8080, () => console.log('Server is up on port ' + 8080));
// spawn.js --------------
const { spawn } = require('child_process');
const child = spawn('node', ['./server.js']);
child.stdout.on('data', data => console.log(data.toString()));
child.stderr.on('data', data => console.log('Error: ' + data));
child.on('close', code => console.log(`Process ended with code ${code}`));
child.on('error', err => console.log(err));
setTimeout(() => child.kill(), 2000);

Child process function not being triggered with no errors

I'm working on a Node.js app utilizing Electron. I need to access a executable in a certain directory and determine its output. The executable is a simple console application. I read the docs on Child Process and tried to use execFile. However, the callback function doesn't seem to execute.
Here's my code at the moment:
var exec = require('child_process').execFile
exec('E:/SteamLibrary/steamapps/common/GarrysMod/bin/gmad.exe', [], function(err, data) {
console.log(err);
console.log(data);
});
How could I go about fixing this?
Youre using windows so execFile() wouldnt work. It stated on docs.. for convenient I use docs example here with litle change.
const { spawn } = require('child_process');
const bat = spawn('C/steam/steam.exe');
bat.stdout.on('data', (data) => {
console.log(data.toString());
});
bat.stderr.on('data', (data) => {
console.log(data.toString());
});
bat.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
});

Need to run a NodeJs application from another NodeJs application

I have a NodeJs application running in the following directory
First Application's Path '/users/user1/projects/sampleProject' which is running at 3000 port.
Second Application's Path '/users/user1/demoProjects/demo1' which is going to run at 5000 port on triggering the router function from first application.
The second NodeJs application is not yet started(It will run at port 5000). It need to run independently on hitting a router function in the first NodeJs Application which is running on port 3000 ie(http://localhost:3000/server/startServer). I'm new to NodeJs child processes, Kindly correct me if i'm wrong. And suggest me a right way to do it. Thanks
Start another node application using node.js?
I have tried it like below
// First NodeJs application
import { exec } from "child_process";
router.get('/startServer', async (req, res, next) => {
console.log("Initiated request")
let startServerInstance = 'cd "/users/user1/demoProjects/demo1" && npm run dev'; // path for the second NodeJs application
console.log("Server instance path => " + startServerInstance)
try {
// exec from child process, Spawns a shell then executes the command within that shell
let child = exec(startServerInstance, function (err, stdout, stderr) {
if (err) throw err;
else {
console.log("result ")
res.json({
status: 'success'
});
}
});
} catch (error) {
res.json({
status: 'error',
message: error
});
}
});
The above code executes the command and triggered the second application to run in background but it doesn't return anything. Either error or success result.
You need to use stout and stderror to check other server logs. Also your code is not correct. If you use if without {} it will not go to else statement. That is why you don't see 'result' text in console.
import {
exec
} from "child_process";
router.get('/startServer', async (req, res, next) => {
console.log("Initiated request")
let startServerInstance = 'cd "/users/user1/demoProjects/demo1" && npm run dev'; // path for the second NodeJs application
console.log("Server instance path => " + startServerInstance)
try {
// exec from child process, Spawns a shell then executes the command within that shell
let child = exec(startServerInstance, function(err) {
if (err) throw err;
console.log("Server started");
});
child.stdout.on('data', (data) => {
// this is new server output
console.log(data.toString());
});
child.stderr.on('data', (data) => {
// this is new server error output
console.log(data.toString());
});
res.json({
status: 'success'
});
} catch (error) {
res.json({
status: 'error',
message: error
});
}
});
Child process callback is only called once the process terminates. If the process keeps running, callback is not triggered.
Explained here - https://nodejs.org/docs/latest-v10.x/api/child_process.html#child_process_child_process_exec_command_options_callback

Resources