javascript — вызывает скрипт Node с PHP exec и возвращает данные в PHP перед методом finally

У меня есть скрипт PHP, который использует exec функция для выполнения сценария Node и возврата некоторых данных обратно в тот же сценарий PHP.

Моя проблема в том, что мне нужно вернуть данные обратно в PHP, не дожидаясь очистки кода в finally заканчивать.

Я написал несколько примеров кода ниже, чтобы показать вам, как работает код, и проиллюстрировать мою проблему. В примере кода не используются никакие модули узлов, но вы можете использовать их, если они помогут.

example.php

$data = 'hello world';

$exec = 'node example.js ' . $data;
$escaped_command = escapeshellcmd($exec);
$data = exec($escaped_command);

// waits 10 seconds then displays returned data
// I need the code to return before finally executes
var_dump($data); // string(31) "Final data is final hello world"

example.js

   let data = process.argv[2];
// let data = "hello world";

async function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

const doSomething = data => new Promise((resolve, reject) => {

if (data) {
resolve("new hello world");
} else {
reject();
}
});

const doSomethingElse = newData => new Promise((resolve, reject) => {

if (newData) {
resolve("final hello world");
} else {
reject();
}
});


(async() => {

try {

let newData = await doSomething(data);

let finalData = await doSomethingElse(newData);

// return this to server/php right now.
// Do not wait until finally script finishes
console.log("Final data is " + finalData);

} catch (err) {

// if error return this to server/php right now.
// Do not wait until finally script finishes
console.log(err);

} finally {

// does cleanup/closes node app
await timeout(10000);
}

})();

1

Решение

использование proc_open запустить процесс асинхронно. Позвольте узлу выводить данные как можно скорее. Эти данные могут быть прочитаны без ожидания завершения узла:

// foo.js
process.stdout.write(JSON.stringify({"foo":"bar"})+"\n");

// simulate cleanup
setTimeout(() => {}, 3000);


// foo.php
<?php

$io = [
0 => ['pipe', 'r'], // node's stdin
1 => ['pipe', 'w'], // node's stdout
2 => ['pipe', 'w'], // node's stderr
];

$proc = proc_open('node foo.js', $io, $pipes);

$nodeStdout = $pipes[1]; // our end of node's stdout
echo date('H:i:s '), fgets($nodeStdout);

proc_close($proc);
echo date('H:i:s '), "done\n";

Образец вывода:

$ php foo.php
14:59:03 {"foo":"bar"}
14:59:06 done

proc_close будет ожидать завершения процесса узла, но вы можете отложить это ожидание, пока не закончите с другими вещами в PHP.

Если вы не вызываете proc_close, вы можете столкнуться с процессами зомби, в зависимости от вашей среды. Docker и проблема пожатия зомби PID 1 содержит хорошее объяснение. Это во многом относится к докеру, потому что именно здесь часто встречаются зомби, но это все же в целом применимо.

В некоторых серверных API есть условия для запуска кода «незаметно» для клиента. Например, fcgi имеет fastcgi_finish_request, который вы можете вызвать до proc_close. Тогда клиенты HTTP не заметят время ожидания.

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

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]