php-Symfonyプロセスコンポーネントを使用してリクエスト中に非同期でSymfonyコマンドを起動する方法は?
Symfonyプロセスコンポーネントを使用してSymfonyコマンドを実行しようとしているので、APIリクエストを取得するときに非同期で実行されます。
Code: 127(Command not found)
というエラーメッセージが表示されますが、コンソールから手動で実行すると、魅力のように機能します。
これは呼び出しです:
public function asyncTriggerExportWitnesses(): bool
{
$process = new Process(['php /var/www/bin/console app:excel:witness']);
$process->setTimeout(600);
$process->setOptions(['create_new_console' => true]);
$process->start();
$this->logInfo('pid witness export: ' . $process->getPid());
if (!$process->isSuccessful()) {
$this->logError('async witness export failed: ' . $process->getErrorOutput());
throw new ProcessFailedException($process);
}
return true;
}
そして、これは私が得るエラーです:
The command "'php /var/www/bin/console app:excel:witness'" failed. Exit Code: 127(Command not found) Working directory: /var/www/public Output:================ Error Output:================ sh: exec: line 1: php /var/www/bin/console app:excel:witness: not found
プロセスコンポーネントの使用法の何が問題になっていますか?
このように呼び出すことも機能しません:
$process = new Process(['/usr/local/bin/php', '/var/www/bin/console', 'app:excel:witness']);
これにより、次のエラーが発生します。
The command \"'/usr/local/bin/php' '/var/www/bin/console' 'app:excel:witness'\" failed.
Exit Code: ()
Working directory: /var/www/public
Output:
================
Error Output:
================
答え :
解決:
まず、プロセスコンポーネントは、親プロセスが停止した後に非同期で実行されることを意図していないことに注意してください。したがって、APIリクエスト中に非同期ジョブをトリガーして実行することは適切なユースケースではありません。
非同期での実行に関する ドキュメントのこれら2つのコメントは、非常に適切です。
子プロセスが完了する前に応答が送信された場合、サーバープロセスは強制終了されます(OSによって異なります)。これは、タスクがすぐに停止されることを意味します。非同期プロセスの実行は、親プロセスを存続させるプロセスの実行と同じではありません。
プロセスが要求/応答サイクルを存続させたい場合は、kernel.terminateイベントを利用して、このイベント内でコマンドを同期的に実行できます。 kernel.terminateは、PHP-FPMを使用する場合にのみ呼び出されることに注意してください。
これを行うと、サブプロセスが終了するまで、前述のPHP-FPMプロセスが新しいリクエストを処理できなくなることにも注意してください。これは、十分に注意しないと、FPMプールをすばやくブロックできることを意味します。そのため、リクエストが送信された後でも特別なことを行わず、代わりにジョブキューを使用する方が一般的にははるかに優れています。
ジョブを非同期で実行する場合は、ジョブを「どこかに」(データベース、redis、テキストファイルなど)保存し、分離されたコンシューマーに「保留中のジョブ」を実行させ、内でジョブをトリガーせずに必要なものを実行します。 APIリクエスト。
上記の実装は非常に簡単ですが、SymfonyMessengerを使用して実装することもできます。 APIリクエストでメッセージをディスパッチし、ジョブキューコンシューマーでメッセージを消費します。
とはいえ、syncメソッドとasyncメソッドを混在させようとしているため、プロセスの使用も失敗しています。
コマンドを呼び出す2回目の試行は、実行可能ファイルを見つけるのに少なくとも成功しますが、ジョブが完了する前にisSuccessful()
run()
代わりに)start()
を使用する場合、ジョブはまだ終了していないため、isSuccessful()
直接呼び出すことはできません。
非同期ジョブを実行する方法は次のとおりです(ただし、これがAPIリクエスト中に役立つことはめったにありません)。
class ProcessCommand extends Command { protected static $defaultName = 'process_bg'; protected function execute(InputInterface $input, OutputInterface $output) { $phpBinaryFinder = new PhpExecutableFinder(); $pr = new Process([$phpBinaryFinder->find(), 'bin/console', 'bg']); $pr->setWorkingDirectory(__DIR__ . '/../..'); $pr->start(); while ($pr->isRunning()) { $output->write('.'); } $output->writeln(''); if ( ! $pr->isSuccessful()) { $output->writeln('Error!!!'); return self::FAILURE; } $output->writeln('Job finished'); return self::SUCCESS; } }
同様の質問
私たちのウェブサイトで同様の質問で答えを見つけてください。