Forked child process keeps terminated with code 1 - node.js

I wrapped a module using Electron Packager. Because it has heavy computation, i put it in a sub process that would be forked from renderer.js when user clicks a button on index.html.
Pseudo-code renderer.js from :
let cp = require('child_process');
let subprocess;
function log(msg) {
// A function to log messages sent from subprocess
}
document.querySelector('#create').addEventListener('click', ev => {
subprocess = cp.fork('./subprocess.js');
log('A subprocess has been created with pid: ' + subprocess.pid + ' with exexPath = ' + process.execPath);
subprocess.on('exit', (code, signal) => log(`child process terminated: signal = ${signal} ; code = ${code}`));
subprocess.on('error', log);
subprocess.on('message', log);
});
The real problem is: this subprocess runs smoothly when i call electron ./ from console in working directory, but the build generated by Electron Packager wouldn't.
The subprocess does not show up in Task Manager, or rather, it is terminated as soon as it appears. The log says child process terminated: signal = null ; code = 1.
Although i guarded at the beginning of subprocess.js with this to catch uncaughtException
process.on('uncaughtException', (err) => {
process.send(`Caught exception: ${err}`);
});
Nothing is recorded in log. What should i do to overcome this situation?
System specs:
Window 10
Node 8.6
Electron 1.7.12
Electron Packager 10.1.2

I have experienced this too. One reason i came up with was because the child process will be the child process of electron itself.
In my case, it will not recognize the node modules i defined.
I suggest using spawn with the spawn process being node.exe. But that will not be practical once you build your app.

Related

Using node.js, I cannot get the stdout from a macos app until the process finishes

I've created a helper app with Xcode. It's a command line app that keeps running using RunLoop (because it will do Bluetooth things in the background).
I want to spawn this app using node.js and read its output. I've sucessufully done this with other applications using the spawn method. However, with this MacOS app nothing is visible until the app finishes.
My node.js code:
const { spawn } = require('node:child_process')
const child = spawn(PROCESS)
child.stdout.on('data', data => {
console.log(data.toString());
})
My Swift code (helper app):
import Foundation
var shouldKeepRunning = true
print("app started")
let controller = Controller()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(10)) {
shouldKeepRunning = false
}
while shouldKeepRunning == true && RunLoop.current.run(mode: RunLoop.Mode.default, before: Date.distantFuture) {
}
In node.js app started is only printed after 10 seconds, when the app finishes. When running the app using Terminal, I see app started immediately.
Does anyone know why this happens and how it can be solved?
Thanks!
This question is actually the same: swift "print" doesn't appear in STDOut but 3rd party c library logs do when running in docker on ECS but instead of node.js Docker is not logging the output.
I fixed it by adding the following to the top of my code:
setbuf(stdout, nil)
This will make print() write to stdout directly without waiting for some buffer to be full first.

Mac spawn startosinstall process with node.js

I'm trying to spawn the startosinstall binary to begin a macOS upgrade. However, I'm seeing startosinstall binary run as root but then a sub process osinstallersetupd gets invoked but seems to run under my standard user account and not root.
Ultimately it breaks the automation because I get hit with an administrative authentication prompt.
auth
Showing the processes: grep
Is this likely an Apple bug/limitation or could it be related to the way of invoking the first binary?
const spawn = require("child_process").spawn;
child = spawn("/Applications/Install macOS High Sierra.app/Contents/Resources/startosinstall",
[
"--applicationpath",
"/Applications/Install macOS High Sierra.app",
"--agreetolicense"
],
{
//maybe try some config options?
}
);
child.stderr.on("data", (data) => {
console.log(data.toString() + "\n");
});
child.stdout.on("data", (data) => {
console.log(data.toString() + "\n");
});
child.on("exit", (code, signal) => {
console.log("child process exited: " + code + "\n");
});
For what it's worth I'm logged in as root and running the script above.
Any help with this is greatly appreciated!
I believe I've found the issue. I am using parts of a script that helps in facilitating upgrades and found that when using the FileVault authenticated reboots you create and load a plist.
macOSUpgrade: https://github.com/kc9wwh/macOSUpgrade/blob/master/macOSUpgrade.sh#L278
However, it seems I was not actually loading the plist and that caused an issue.
tl;dr I wasn't loading the plist: https://github.com/kc9wwh/macOSUpgrade/blob/master/macOSUpgrade.sh#L337

Open apps using node.js spawn

I'm trying to do a little application with node.js that would run on mac and execute some commands.
I've successfully used spawn to run command lines such as xcodebuild, but xcrun doesn't seems to work when I try to open the iOS Simulator.
I can open on terminal by typing:
xcrun instruments -w 'iPhone 5s (9.2)' -t <template>
But if I use node and try to use spawn like this:
var args = ['instruments', '-w', `iPhone 5s (9.2)`, '-t', 'noTemp'];
var xcrun = spawn('xcrun', args);
So it got me thinking that maybe it had some limitation opening apps? I tried to run:
var args = ['/Applications/Spotify.app'];
var xcrun = spawn('open', args);
And nothing happens. I couldn't find anything related to that. My question is: is there anyway to open apps using node.js spawn? If there is, does someone know what's the problem with my code?
Here's the full code if needed:
var args = ['instruments', '-w', `${fullDevice}`, '-t', 'noTemp'];
var xcrun = spawn('xcrun', args);
xcrun.stdout.on('data', (data)=>{
console.log(data.toString('utf8'));
})
xcrun.on('close', (code) => {
socket.emit({
time: commands.getCurrentTime(),
type: 'success',
log: 'Device booted...'
});
callback();
if (code !== 0) {
console.log(`open process exited with code ${code}`);
}
});
OBS: if I run this piece of code the application doesn't terminate, the program doesn't continue and nothing happens.
EDIT: Changed:
xcrun.on('data', (data)=>{
To:
xcrun.stdout.on('data', (data)=>{
Spawned processes have two separate streams for stdout and stderr, so you will need to listen for data on those objects and not the spawned process object itself:
xcrun.stdout.on('data', function(data) {
console.log('stdout: ' + data.toString());
});
xcrun.stderr.on('data', function(data) {
console.log('stderr: ' + data.toString());
});
The problem was one line above. Not sure why, but there's a socket.emit call that is wrong and actually hold the program's execution.

node.js python child-process won't print in realtime

I'm trying to make a python program's stdout trigger an event for my node.js app to detect it and send that stdout's data to a client's browser.
The problem is the program won't deliver it's stdout until it terminates... and closes the pipe i guess.
I need it to be so as a line prints node gets the stdout after each print statement.
here's an example python program run with python program.py
from __future__ import print_function
import time
import os
import sys
for num in range(0,8):
print('my []-- ', num)
time.sleep(0.2)
sys.stdout.flush()
Node which spawns a child process with
proc = spawn('python3 program.py -u')
var pid = proc.pid
echoIO( pid )
toggleState()
processDriver(proc)
below listens for the stdout and sends it to a browser with socket io
function processDriver(proc) {
proc.stdout.setEncoding('utf-8');
proc.stdout.on('data', function (data) {
echoIO(data)
})
proc.stderr.on('data', function (data) {
console.log(data)
var res = data.toString()
echoIO(res)
})
proc.on('exit', function (code) {
console.log(code)
stateOff()
echoIO("exit " + code)
sendProcState(JSON.parse('{"status":"not_running"}'))
})
}
Also i've tested this problem in raspbian, ubuntu, and crunchbang, and the issue persists, no other solutions i've found on stackoverflow have worked yet. Sorry if this is about the 20th post.
EDIT:
I've also run into this now
stderr - execvp(): No such file or directory
events.js:72
throw er; // Unhandled 'error' event
^
Error: spawn ENOENT
...
proc = spawn('python', ['program.py'], '-u')
it turns out my method of spawning the child was the error. It's a miracle that it ever spawned a child at all, playing with the code generated the error above, that led me to the post below.
But once I spawned it with this line, instead of a string with 'python program.py -u' it worked.
Node.js - spawned process is generating error "execvp(): No such file or directory"

NodeJS not spawning child process except in tests

I have the following NodeJS code:
var spawn = require('child_process').spawn;
var Unzipper = {
unzip: function(src, dest, callback) {
var self = this;
if (!fs.existsSync(dest)) {
fs.mkdir(dest);
}
var unzip = spawn('unzip', [ src, '-d', dest ]);
unzip.stdout.on('data', function (data) {
self.stdout(data);
});
unzip.stderr.on('data', function (data) {
self.stderr(data);
callback({message: "There was an error executing an unzip process"});
});
unzip.on('close', function() {
callback();
});
}
};
I have a NodeUnit test that executes successfully. Using phpStorm to debug the test the var unzip is assigned correctly
However if I run the same code as part of a web service, the spawn call doesn't return properly and the server crashes on trying to attach an on handler to the nonexistent stdout property of the unzip var.
I've tried running the program outside of phpStorm, however it crashes on the command line as well for the same reason. I'm suspecting it's a permissions issue that the tests don't have to deal with. A web server spawning processes could cause chaos in a production environment, therefore some extra permissions might be needed, but I haven't been able to find (or I've missed) documentation to support my hypothesis.
I'm running v0.10.3 on OSX Snow Leopard (via MacPorts).
Why can't I spawn the child process correctly?
UPDATES
For #jonathan-wiepert
I'm using Prototypical inheritance so when I create an "instance" of Unzipper I set stdout and stderr ie:
var unzipper = Unzipper.spawn({
stdout: function(data) { util.puts(data); },
stderr: function(data) { util.puts(data); }
});
This is similar to the concept of "constructor injection". As for your other points, thanks for the tips.
The error I'm getting is:
project/src/Unzipper.js:15
unzip.stdout.on('data', function (data) {
^
TypeError: Cannot call method 'on' of undefined
As per my debugging screenshots, the object that is returned from the spawn call is different under different circumstances. My test passes (it checks that a ZIP can be unzipped correctly) so the problem occurs when running this code as a web service.
The problem was that the spawn method created on the Object prototype (see this article on Protypical inheritance) was causing the child_process.spawn function to be replaced, so the wrong function was being called.
I saved child_process.spawn into a property on the Unzipper "class" before it gets clobbered and use that property instead.

Resources