この投稿では、supervisord を使用して symfony コマンドの実行を処理する方法を学びます。基本的に、supervisord により次のことが可能になります:
プロセスの実行を自動化するために Unix の crontab を利用することがあります。ほとんどの場合、これで機能しますが、問題が発生する可能性があります。
ユーザーの通知を記録するデータベース テーブルがあると想像してみましょう。テーブルには次の情報が保存されます:
一方、次のステップに従って実行されるコマンドをコーディングしました。
Linux crontab でこのコマンドを頻繁に (1 分、2 分など) 実行するように設定しました。ここまでは順調です。
現在のプロセスが 500 件の通知をクエリし、400 件を送信したときに新しいプロセスが開始すると想像してみましょう。これは、新しいプロセスが、最後のプロセスによってまだ更新されていない 100 件の通知と新しい通知をクエリすることを意味します:
両方のプロセスが通知をクエリしているため、これらの 100 件の通知が 2 回送信される可能性があります。
解決策として、スーパーバイザーを使用することができます。これによりプロセスが実行され続け、必要に応じて再起動されます。このようにして、プロセスを 1 つだけ保持し、重複を避けます。コマンドがどのようになるべきかを分析してみましょう:
#[AsCommand( name: 'app:notification' )] class NotificationCommand extends Command { private bool $forceFinish = false; protected function configure(): void { $this ->addOption('time-limit', null, InputOption::VALUE_OPTIONAL, 'Max time alive in seconds') ->addOption('time-between-calls', null, InputOption::VALUE_OPTIONAL, 'Time between every loop call') ; } protected function execute(InputInterface $input, OutputInterface $output): int { $this->forceFinish = false; pcntl_signal(SIGTERM, [$this, 'signalHandler']); pcntl_signal(SIGINT, [$this, 'signalHandler']); $timeLimit = $input->getOption('time-limit'); $timeBetweenCalls = $input->getOption('time-between-calls'); $dtMax = (new \DateTimeImmutable())->add(\DateInterval::createFromDateString("+ {$timeLimit} seconds")); do{ // Here we should execute a service to query and send notifications // ...... sleep($timeBetweenCalls); $dtCurrent = new \DateTimeImmutable(); }while($dtCurrent < $dtMax && !$this->forceFinish); return Command::SUCCESS; } public function signalHandler(int $signalNumber): void { echo 'Signal catch: ' . $signalNumber . PHP_EOL; match ($signalNumber) { SIGTERM, SIGINT => $this->forceFinish = true, default => null }; } }
コマンドをステップごとに説明してみましょう:
configure メソッドは、オプションを入力することを宣言します。
execute メソッドは次のように動作します:
signalHandler 関数は、SIGTERM および SIGINT Unix シグナルをキャッチします。 SIGINT は Ctrl+C を押したときに送信されるシグナルであり、SIGTERM は kill コマンドを使用するときのデフォルトのシグナルです。 signalHandler 関数がそれらを検出すると、forceFinish 変数を true に設定します。これにより、forceFinish 変数が設定されているため、現在のループが終了するとコマンドが終了します。もはや偽りではありません。これにより、ユーザーは最大日付が終了するまで待つことなくプロセスを終了できます。
これまでにコマンドを作成しました。次に、スーパーバイザがそれを処理できるようにセットアップします。設定を始める前に、スーパーバイザをインストールする必要があります。次のコマンドを実行して実行できます:
sudo apt update && sudo apt install supervisor
インストール後、次のコマンドを実行してスーパーバイザが実行されていることを確認できます。
sudo systemctl status supervisor
スーパーバイザー設定ファイルは、フォルダー /etc/supervisor/conf.d に配置されます。 notif.conf という名前のファイルを作成し、次の内容を貼り付けましょう:
command=php <your_project_folder>/bin/console app:notifications --time-limit=120 --time-between-calls=10 user=<your_user> numprocs=1 autostart=true autorestart=true process_name=%(program_name)s_%(process_num)02d
各キーについて説明しましょう:
この構成では、app:notifications コマンドは最大 120 秒間実行され、ループごとに 10 秒間スリープします。 120 秒が経過するか、UNIX シグナルをキャッシュした後、コマンドはループを抜けて終了します。その後、スーパーバイザーが再度開始します。
スーパーバイザーを使用して、crontab を使用せずにコマンドを実行し続ける方法を学習しました。これは、crontab によって起動されたプロセスが重複してデータ破損を引き起こす可能性がある場合に役立ちます。
私が書いた最後の本では、スーパーバイザーを使用して symfony メッセンジャーワーカーを実行し続ける方法を示しました。さらに詳しく知りたい場合は、次の書籍を参照してください: PHP と Symfony フレームワークを使用した操作指向の API の構築: ステップバイステップ ガイド
以上がスーパーバイザーを使用して Symfony コマンドの実行を処理するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。