Running NodeJS as a service in Windows with child process - node.js

I've got two NodeJS servers running on Windows, one listening for incoming requests which then shapes the request and then hands the request off to a worker server. The worker server will take the inputs from the controller and perform several functions: log the event with the DB, shell out to perform an action through a child process, evaluate the results and finally return the results back to the controller.
When I run both processes through Powershell or cmd everything runs fine. If I run the Controller as a service with NSSM and the Worker on Powershell everything works fine. However, if I run the Worker server as a service with NSSM the child processes fail (console.logs or using something like bunyon seem to be swallowed up so debugging is difficult). Is there any way to run NodeJS as a server if it needs to execute child processes?

If I understood you correctly, you can try redirecting the stdout and stderr stream of the worker using
var fs = require('fs'),
spawn = require('child_process').spawn,
out = fs.openSync('./out.log', 'a'),
err = fs.openSync('./out.log', 'a');
var child = spawn('prg', [], {
detached: true,
stdio: [ 'ignore', out, err ]
});
child.unref();
This way while spawning, we are giving an fd to the worker process to write the output to the file.

Related

Minecraft/Node - Writing to process.stdin and Child Process Also Receiving Input

I'm trying to write a terminal application that would allow me to start and stop a Minecraft server, write arguments through readline that would first be checked by the Node process and then, if determined by the script, sent to the Minecraft server for use instead.
Running on Windows 10 with latest Node build and Minecraft JE server.
First I tested out just starting up a node process that spawned in a child process holding the Minecraft server. I set the 3 stdio arguments to 'inherit' and also 'ipc' (not 100% sure why this is necessary, but I saw others do it). Once run, if I typed anything into the terminal the Minecraft server would receive input through Node. This was great. What I wanted, though, was to be able to run readline and parse inputs and determine whether Node should process the input or if they should be sent to the Minecraft server.
So I played around with the stdio arguments and using process.stdin.write() and such, trying to figure out how to write to the child process' stdin so that the Minecraft server would receive the input, but to no avail.
So I tried running a "master" Node process that would fork a secondary Node process. The "master" would run readline, and use child.send() if any input was to be sent there. Then, in the second Node process, I would start the Minecraft server as a spawn with all 3 stdio arguments set to inherit. I would then listen with process.on('message') and if a message was received, write it to process.stdin hoping the Minecraft process would receive it through inherited input. But this also did not work.
I've tried a number of different things, but in the end I haven't had any luck. I've tried looking up as much as I could, but I haven't found anything that would help me out. Sorry if this ends up being a no-brainer.
// First Iteration
// spawns in a minecraft server and listens for input in the terminal
// effectively the same as running the equivalent run command for the minecraft server, except this runs as a Node child process
const spawn = require('child_process').spawn
var minecraft = spawn('java', ['-jar', '-Xms1G','-Xmx1G', '-Dfile.encoding=utf8', '../spigot-1.13.2.jar'], {
stdio: [
'inherit',
'inherit',
'inherit',
'ipc'
],
})
// Second Iteration
// changed cp stdin to pipe and tried to write manually via rl
const spawn = require('child_process').spawn
const readline = require('readline')
var minecraft = spawn('java', ['-jar', '-Xms1G','-Xmx1G', '-Dfile.encoding=utf8', '../spigot-1.13.2.jar'], {
stdio: [
'pipe',
'inherit',
'inherit',
'ipc'
],
})
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
}).on('line',(line)=> {
process.stdin.write(line)
})
// Later iterations involved running nested child processes, basically, but were all more or less more-abstract versions of my second iteration.
What I'd like to achieve, as I said earlier, is being able to listen for admin input from the terminal with readline and, as appropriate, send that input to the Minecraft server process. Otherwise, readline input would be processed in the Node process.
** to clarify, when I say it doesn't work, what I mean is that I get no response from the Minecraft server process. Nothing in-game, nothing on the command line. With my first iteration, I could see output from the Minecraft process both in-game and on the command line. But by the second iteration, nothing.
You cannot write to process.stdin. Did you mean to write to the stdin of the minecraft process mincraft.stdin?
minecraft.stdin.write(line)

Receive output of debug function from child process in parent

so, what am I trying to achieve:
I am running master process, which forks 2 other node processes. I am using this debug library from npm and I need it's output (of the debug function function) of child processes to be piped to parent's outputs (stdout, stderr).
Currently what I'm getting successfully piped is console.log("..."); but not:
var log = require('debug')('service');
log.color = 3;
log("...");
I am forking child processes using this code:
var fork = require('child_process').fork;
var child_options = {
cwd: __dirname,
env: process.env,
stdio: [ 'ignore', process.stdout, process.stderr, 'ipc' ],
deatached: false,
shell: true
};
var job_node = fork('job_node', [], child_options);
Could anyone help me find out what the problem might be? Thank you :)
EDIT:
This problem is probably not caused by some kind of error in stream piping -
instead there is something with existing/non-existing console window, attached terminal.
When I tried to run the server from within PhpStorm, using built-in tools, it showed ONLY the console.log function outputs even from master process.
TheKronnY
Solved:
Just for the sake of trying, I tried to use debug.enable function in the master process and it worked.
I used debug.enable('master,job,service'); to enable used namespaces in other processes and it worked, so I do not know why, but other namespaces, created in the child processes were disabled by default.

NodeJS: exit parent, leave child alive

i am writing an utility. One command of this utility is to run an external application.
var child_process = require('child_process');
var fs = require('fs');
var out = fs.openSync('.../../log/out.log', 'a');
var err = fs.openSync('.../../log/err.log', 'a');
exports.Unref = function(app, argv) {
var child = child_process.spawn(app, argv, {
detached: true,
stdio: [ 'ignore', out, err ]
});
child.unref();
//process.exit(0);
};
Currently:
$ utility run app --some-args // run external app
// cant enter next command while app is running
My Problem is that if i run this command, the terminal is locked while the "external" Application is running.
But the terminal window shouldn't be locked by the child_process.
i wanna run:
$ utility run app --some-args
$ next-command
$ next-command
The external Application (a desktop application) will be closed by hisself.
Like this:
$ subl server.js // this runs Sublime Text and passes a file to the editor
$ npm start // The terminal does not locked - i can execute next command while Sublime is still running
You know what i mean ^^?
Appending ['>>../../log/out.log', '2>>../../log/err.log'] to the end of argv instead of leaving two files open should work since it's the open file handles that are keeping the process alive.
Passing opened file descriptors in stdio in addition to detached: true will not work the way you expect because there is no way to unref() the file descriptors in the parent process and have it still work for the child process. Even if there was a way, I believe that when the parent process exited, the OS would clean up (close) the file descriptors it had open, which would cause problems for the detached child process.
The only possible way that this might have been able to work would have been by passing file descriptors to child processes, but that functionality was dropped several stable branches ago because the same functionality did not exist on some other platforms (read: Windows).

node.js forever daemon, how to exit properly?

When using forever to run a node.js program as a daemon
i.e.
forever start myNodeTask
If the daemon (myNodeTask) decides it needs to exit, what is the correct way to do so?
If I just call process.exit() the program does terminate but it doesn't delete the forever log file, which leads me to believe that I need the program to exit in a more forever-friendly manner.
The node tasks I'm running are plain tcp servers that stream data to connected clients, not web servers.
The forever module always keeps the log files, even after a process has finished. There is no forever-friendly manner to delete those files.
But, you could use the forever-monitor module, which allow you to programatically use forever (from the docs):
var forever = require('forever-monitor'),
fs = require('fs');
var child = new (forever.Monitor)('your-filename.js', {
max: 3,
silent: true,
options: []
});
child.on('exit', function () {
console.log('your-filename.js has exited after 3 restarts');
// here you can delete your log file
fs.unlink('path_to_your_log_file', function (err) {
// do something amazing
});
});
child.start();

How to start a process in node.js that thinks its being run from the commandline

I'm running require('child_process').exec('npm install') as a child process in a node.js script, but I want it to retain console colors. I'm running in windows, but want this script to be portable (e.g. to linux). How do I start a process that think's it's being run from the console?
Note: I'd rather not have npm-specific answers, but an answer that allows me to trick any command.
You can do this by letting the child process inherit the master process' stdio streams. This means you need to user spawn rather than exec, and this what you'd do:
var spawn = require('child_process').spawn;
var child = spawn('npm', ['install'], {
stdio: 'inherit'
});

Resources