node ebusy when spawning .exe - javascript

I'm working with a temp file that's downloaded from a server. but when I ran it on macOS, it ran fine. and did what it was supposed to do. but when I ran it on windows, it keeps giving me an EBUSY error when trying to spawn the child.
I tried delaying the start of the file. tried to remove the chmod so it just runs on Linux and macOS. But still getting the Ebusy error. Am I doing something wrong?
Note:
I can launch the binary from another node instance outside. Like from a cmd. but launching it from the node instances that created it leads to a Ebusy error.
temp.open('', (err, info) => {
if (err) throw err;
console.log('File: ', info.path);
console.log('Filedescriptor: ', info.fd);
var data = fs.createWriteStream(info.path);
res.data.pipe(data);
data.on('close', async () => {
fs.chmodSync(info.path, 0o755);
await delay(1000);
var child = cp.spawn(info.path, [key, jwt], { stdio: ['inherit', 'inherit', 'inherit', 'ipc'] });
Error:
Error: spawn EBUSY
at ChildProcess.spawn (node:internal/child_process:415:11)
at Object.spawn (node:child_process:707:9)
at WriteStream.<anonymous>
at WriteStream.emit (node:events:394:28)
at emitCloseNT (node:internal/streams/destroy:138:10)
at processTicksAndRejections (node:internal/process/task_queues:82:21) {
errno: -4082,
code: 'EBUSY',
syscall:
Edit:
I created a new module to try to spawn the child that way. it will be forked in the main process. but I'm still getting the same error in the fork. still the same error.
const cp = require('child_process')
const childpath = process.argv[2]
var argv = [];
for (let index = 3; index < process.argv.length; index++) {
const element = process.argv[index];
argv.push(element)
}
console.log(argv)
var child = cp.spawn(childpath, argv, {
stdio: ['inherit', 'inherit', 'inherit', 'ipc']
})
child.on('message', (msg) => {
if (process.send) process.send(msg)
else process.emit('message', msg)
})
child.on('error', (msg) => {
console.log(msg)
process.emit('error', msg)
})
child.on('close', (msg) => {
process.exit(msg)
})
Update:
I've noticed that I cannot run the file until the process the created it is ended. meaning that the process that needs to use it is using it. but I cannot do the thing I want to do with it.EI spawn it
Update 2:
The next thing I tried was to create a symbolic link with the node. And still nothing but I noticed that the file doesn't become runnable until the main process is ended. which means that the process that I'm running has something to do with it. So I need to be able to unlike it from the process that's running. it seems like windows need to do some initialization after the file is made. and because it's still connected to the main process in some way it's not able to. Im guess this is why when I ended the process, the node icon showed up on the symlink and that's why I'm able to run it manually.
Final Update:
I'm gonna work on a file system module that acts like temp files but is just regular files. that the process is tracking. giving the function of temp files but not really. this will allow me to use the function of temp files but without the file being unable to be executed. It seems like making it a temp file made it so it could not be executed by the same process that created it. it seems like a windows file system thing and how they handle temp file permissions.

The way Temp files are handled in windows is different than macOS. to my best estimate, it seems like Temp files in windows are linked to the process that created them and aren't able to be changed or accessed by that process. The problem lies in trying to execute these temp files which windows has assigned to a process already making it unassignable. NodeJs needs to be able to access the file to be able to launch it and windows permission will not allow it until the main process is killed or ended. this unlinks the file from that process making it accessible to the rest of the system.

Related

How can I use a child process to run a .class file from a parent directory?

In this case, I am using Node.js ChildProcess. Let's say the application file (index.js, for example) is in folder1. This folder also has folder2, which is where the class file is. So, when I call spawn from folder1, the command's current directory is folder1. However, I can't do java ./folder2/MyFile.
Here's what I tried:
async function run(path){
let child = spawn('java', [path], {
stdio: [process.stdin, process.stdout, process.stderr] //for testing purposes
})
}
Using function run on ./folder2/MyFile returns:
Error: could not find or load main class ..folder2.MyFile
I assume this has something to do with java and classpath. I saw an answer involving setting the classpath to the target directory (folder2) but it didn't do anything.
In short, how can I run a .class file from a different directory?
You can use exec instead of spawn so you can use two commands with & symbol which the second command runs when the first one finish without fail.
I think this might work for you.
const exec = require('child_process').exec;
exec("cd ./folder2 & java MyFile", function(
error: string,
stdout: string,
stderr: string
) {
console.log(stdout);
console.log(error);
console.log(stderr);
});

How to run daemon within a js file

I'm trying to start a server daemon from within my js code, then to access it from the same program. However, when I use the execFile() method from the child_process module, this blocks the entire program: the execFile() call never stops, and I am unable to access the server. However, I know the daemon is started since I see a process of the same name start up from my activity monitor (macos equivalent of task manager).
I've also tried exec() and spawn() from the same module, and it gave the same results.
What I'd want to be able to do is to start the daemon as a separate process, forget about it, then stop it when I'm done using it. Is there any way I could do at least the first two?
Here is my code (the runArduino function is where I start the daemon, and the main() function is where I access it):
const grpcLib = require('grpc');
const protoLoader = require('#grpc/proto-loader');
const pathLib = require("path");
const utilLib = require('util');
const exec = utilLib.promisify(require('child_process').execFile);
const RPC_PATH = pathLib.join(__dirname, "arduino-cli/rpc")
var PROTO_PATH = pathLib.join(RPC_PATH, "/commands/commands.proto");
const options = {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
includeDirs:
[
RPC_PATH
]
}
const packageDefinition = protoLoader.loadSync(PROTO_PATH, options);
const arduinoCli = grpcLib.loadPackageDefinition(packageDefinition).cc.arduino.cli.commands;
function runArduino()
{
exec(__dirname+"/arduino-cli_macos", ['daemon'],function(err, data)
{
console.log(err);
console.log(data);
});
}
function main()
{
var client = new arduinoCli.ArduinoCore('localhost:50051', grpcLib.credentials.createInsecure());
client.Version({}, function(err, response){
console.log("Running version: ", response); //returns a version number
});
}
runArduino();
main();
The first time I run it, this is what I get (execution doesn't stop):
Running version: undefined
Once the daemon is up and I run it, I get this (I am able to access the server now and execution does end):
Running version: { version: '0.11.0' }
Error: Command failed: /Users/Herve/Desktop/MyStuff/ArduinoX/ArduinoX/arduino-cli_macos daemon
Failed to listen on TCP port: 50051. Address already in use.
at ChildProcess.exithandler (child_process.js:303:12)
at ChildProcess.emit (events.js:315:20)
at maybeClose (internal/child_process.js:1021:16)
at Socket.<anonymous> (internal/child_process.js:443:11)
at Socket.emit (events.js:315:20)
at Pipe.<anonymous> (net.js:674:12) {
killed: false,
code: 5,
signal: null,
cmd: '/Users/Herve/Desktop/MyStuff/ArduinoX/ArduinoX/arduino-cli_macos daemon'
}
I believe you should either await the exec or run main() in exec's callback. Right now your main() executes before child process is started.
exec(__dirname+"/arduino-cli_macos", ['daemon'],function(err, data)
{
console.log(err);
console.log(data);
});
This is why at the first run you're getting undefined. Child process is not killed automatically, I guess, this is why at second run you can do the RPC, but can't really start the child process again, as it's already running (and is occupying the 50051 port).
If your application is starting the child process, I believe it has to take care of killing it as well:
var childProcessHandler = exec(__dirname+"/arduino-cli_macos", ['daemon'],function(err, data)
{
console.log(err);
console.log(data);
});
// ... and later in your code:
childProcessHandler.kill()
This way you could start/stop the application without having to worry about cleaning the processes. Only thing which you have to consider is taking care of cleanup in case an exception occurs.
Edit okay, it appears that to start process as a daemon, you'd have to use spaw with detached option:
const { spawn } = require('child_process');
const child = spawn(__dirname+"/arduino-cli_macos", {
detached: true
});
child.unref();

How to access command prompt when starting node.js server?

I have a node.js server set up and would like to send something to the command prompt on start up (because I couldn't figure out how to do it when the server was already running).
Do I do this from the server.js file? And what would the code look like?
I currently have this argument, which works when I normally access the windows command prompt on my own:
C:\Users\path\python.exe C:\Users\path\test.py
Server.js:
const exec= require("child_process").exec;
const pythonProcess =
exec("C:/Users/myPath/python.exe",
["C:/Users/myPath/test.py"]);
Everything compiles, and the server starts, but there is no evidence that the python file has been run. (When it normally runs, there is a document saved on my desktop) Am I doing something wrong?
Thank You.
It sounds like you're wanting to spawn a python process from a node process. You probably want to use Node's child_process.spawn() instead of child_process.exec(). Node's child_process.exec() is
asynchronous, and
buffer stdout and stderr, so you won't see any of their output until the callback on the exec() is invoked when the child process exits... and since you haven't given it a callback, you'll never see it.
Try something like this:
const childProcess = require('child_process') ;
const python = '.../python.exe' ;
const argv = [
'.../test.py',
] ;
const child = childProcess.spawn( python, argv, {
detached: false,
stdio: [
'inherit', // inherit STDIN from the parent process
'inherit', // inherit STDOUT from the parent process
'inherit', // inherit STDERR from the parent process
],
shell: false,
}) ;
child.on('error', ( err ) => {
console.log(`${python}: ${err.stack}`) ;
}) ;
child.on('exit', (code, signal) => {
console.log(`${python}: exited with exit code ${code}, signal '${signal}'`) ;
}) ;
But if all you're trying to do here is kick off a python program... why don't you do that via a shell script (on Windows, either a "batch" file (*.cmd) file or a Powershell script (*.ps)?

How do I stop Tomcat using shutdown.bat in app.on ("before-quit")?

I try to start and stop a Tomcat instance on Windows using Electron.
I have modified the electron-quick-start project to stop my Tomcat instance with a batch file which calls Tomcat's shutdown.bat when all Electron windows are closed or before my application exits.
However, when I close my application, there is no output from the shutdownTomcat.on ("data", ...) and shutdownTomcat.on ("exit", ...) listeners. The only output is from a console.log ("Hello world") from my app.on ("before-quit", ...).
I chose this approach because I am new to Electron and want to test NodeJS' spawn's behaviour.
When I use my code outside of the app.on () listeners, the output is shown but my Tomcat instance is not being stopped. However, my startTomcat.bat file, which calls Tomcat's startup.bat, works without any problems.
I already read NodeJS' childProcess' documentation ("Spawning .bat and .cmd files on Windows"), but I cannot get it to work; which leads to my question, namely where the problem is and what I'm doing wrong.
My Main.js file I use for the main process:
const { app, BrowserWindow } = require('electron');
const { spawn } = require('child_process');
const path = require('path');
const start = path.resolve("./start.bat");
const startTomcat = spawn('cmd.exe', ['/c', start], {
cwd: process.cwd(),
detached: true,
});
// ...
app.on('before-quit',()=> {
const shutdownTomcat = spawn('cmd.exe', ['/c', stop], {
detached: true
// stdio: 'ignore'
});
shutdownTomcat.stdout.on('data', (data) => {
console.log("This data won't show up...", data);
});
shutdownTomcat.stderr.on('data', (data) => {
console.log(data.toString());
});
shutdownTomcat.on('exit', (code) => {
console.log(`Child Shutdown Tomcat exited with code ${code}`);
});
console.log("Hello World");
});
And finally, the batch file (stop.bat) I'm using to call Tomcat's shutdown.bat:
cd /D "%~dp0"
cd "..\\apache-tomcat\\bin"
call shutdown.bat
Most probably your electron application is already terminated by the time your events would have fired. Therefore there is no longer reference to your spawned process and listeners.
You can try event.preventDefault() to cancel the app quitting. Then you can explicitly app.quit() once you are done (but beware of infinitely looping through your before-quit listener; you may remove it or app.exit(0)).

Execute a JS file (with logs, etc...) inside another NodeJS process

Here is my problem, I want to create a CLI that automatically runs a test. Without the CLI, I'm able to run everything perfectly with the node command:
node test.js
Basically, I want to do the exact same thing as the command before, so I googled for a technique that does this. I found this:
#!/usr/bin/env node
'use strict';
const options = process.argv;
const { execFile } = require('child_process');
const child = execFile('node', ['../dist/test.js'], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout);
});
This method doesn't work for me because, in the test.js file, I'm using the ora package. And because this package is making real-time animations, it doesn't come in stdout.
Is there any way of executing in real time (without subprocess) my test.js using Node? I'm open to other methods, but I want to publish the CLI on NPM, so keep in mind that it has to be in JavaScript 😊.
You can find every file that I've talked here on GitHub. Normally, you wouldn't need this link, but I'm giving it to you if you need to have a closer look.
You should simply call your test() function from your CLI code, after requiring the module that defines it. Have a look at mocha and jasmine: you will see that while both tools provide a CLI, they also provide instructions for invoking the test frameworks from arbitrary JS code.
I can't think of a way without a sub-process. but this may help.
The child process exec will not work with the continuous output commands as it buffers the output the process will halt when that buffer is full.
The suitable solution is spwan :
var spwan = require('child_process').spwan
var child = spwan('node', ['../dist/test.js'])
child.stdout.on('data', function(data) {
console.log(data)
})
child.stderr.on('data', function(data) {
console.log(data)
})
Here is my solution, you can use the fs library to get the code of the file, and then, you simply use eval to execute in the same process.
const fs = require("fs");
function run(file) {
fs.readFile(file, (err, data) => {
eval(data.toString('utf8'))
})
}

Categories