Как запустить демона в файле js

#javascript #node.js #daemon

#javascript #node.js #демон

Вопрос:

Я пытаюсь запустить демон сервера из своего js-кода, а затем получить к нему доступ из той же программы. Однако, когда я использую execFile() метод из модуля child_process, это блокирует всю программу: execFile() вызов никогда не останавливается, и я не могу получить доступ к серверу. Однако я знаю, что демон запущен, поскольку я вижу, что процесс с тем же именем запускается с моего монитора активности (эквивалент диспетчера задач macos).

Я также пробовал exec() и spawn() из того же модуля, и это дало те же результаты.

Что я хотел бы иметь возможность сделать, так это запустить daemon как отдельный процесс, забыть о нем, а затем остановить его, когда я закончу его использовать. Есть ли какой-либо способ, которым я мог бы выполнить хотя бы первые два?

Вот мой код ( runArduino функция — это то, где я запускаю демон, а main() функция — это то, где я получаю к нему доступ):

 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();

  

При первом запуске я получаю вот что (выполнение не останавливается):

 Running version:  undefined

  

Как только демон запущен, и я запускаю его, я получаю это (теперь я могу получить доступ к серверу, и выполнение заканчивается):

 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'
}
  

Ответ №1:

Я считаю, что вам следует либо await запустить exec, либо выполнить main() обратный вызов exec. Прямо сейчас ваш main() выполняется до запуска дочернего процесса.

 exec(__dirname "/arduino-cli_macos", ['daemon'],function(err, data)
    {
        console.log(err);
        console.log(data);
    });
  

Вот почему при первом запуске вы получаете undefined . Я думаю, дочерний процесс не завершается автоматически, поэтому при втором запуске вы можете выполнить RPC, но не можете снова запустить дочерний процесс, поскольку он уже запущен (и занимает порт 50051).

Если ваше приложение запускает дочерний процесс, я считаю, что оно также должно позаботиться о его уничтожении:

 var childProcessHandler = exec(__dirname "/arduino-cli_macos", ['daemon'],function(err, data)
    {
        console.log(err);
        console.log(data);
    });
// ... and later in your code:
childProcessHandler.kill()
  

Таким образом, вы могли бы запускать / останавливать приложение, не беспокоясь об очистке процессов. Единственное, что вам нужно учитывать, это позаботиться об очистке в случае возникновения исключения.

Редактировать хорошо, похоже, что для запуска процесса в качестве демона вам придется использовать опцию spaw with detached :

 const { spawn } = require('child_process');

const child = spawn(__dirname "/arduino-cli_macos", {
  detached: true
});

child.unref();
  

Комментарии:

1. Я понимаю, что вы имеете в виду, но когда я вызываю main() обратный вызов или ожидаю, exec() чтобы вернуть дочерний процесс, main() в конечном итоге никогда не вызывается. Мне кажется, что вызов exec() на самом деле никогда не заканчивается, так как childProcessHandler никогда не назначается. Я не знаю, типично ли такое поведение для демонов. Когда я вызываю команду arduino-cli_macos daemon непосредственно в командной строке, она не завершается, пока я не выйду из консоли, поэтому я думаю, что это связано с этим.

2. Хм … кстати, где ты это взял daemon ? Я нигде не вижу этого в спецификации … если вы хотите передать аргументы в свой cmd, это должно быть в первом аргументе после пробела.

3. Спасибо! Теперь я могу правильно запускать и завершать демон. К сожалению, я по-прежнему не могу получить доступ к серверу по какой-либо причине, но поскольку на мой вопрос был дан ответ, я отмечу это как правильное.

4. Демон запускается двоичным файлом arduino-cli, при запуске открывается его интерфейс grpc.