この投稿では、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 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/bin/console app:notifications --time-limit=120 --time-between-calls=10 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 の構築: ステップバイステップ ガイド
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3