在這篇文章中,我們將學習如何使用supervisord來處理symfony指令的執行。基本上,supervisord 將允許我們:
有時我們會使用 unix crontab 來自動執行進程。這可能在大多數情況下有效,但在某些情況下可能會導致問題。
假設我們有一個記錄使用者通知的資料庫表。此表儲存以下資訊:
另一方面,我們編寫了一個命令,其執行遵循以下步驟:
我們在 Linux crontab 中設定此命令每隔一段時間運行一次(1 分鐘、2 分鐘等)。到目前為止一切順利。
現在假設當前進程已查詢 500 個通知,當發送 400 個通知時,一個新進程啟動。這意味著新進程將查詢上一個進程尚未更新的 100 條通知以及新的通知:
這可能會導致這 100 個通知發送兩次,因為兩個進程都查詢了它們。
作為解決方案,我們可以求助於使用supervisor。它將保持我們的進程運行並在需要時重新啟動它。這樣,我們只保留一個進程並避免重疊。讓我們來分析一下指令應該是什麼樣子:
#[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 變數為不再虛假。這允許用戶終止進程,而不必等到最大日期完成。
到目前為止,我們已經建立了命令。現在是時候設定主管了,以便它可以處理它。在開始設定之前,我們必須安裝supervisor。您可以執行以下命令來完成此操作:
sudo apt update && sudo apt install supervisor
安裝後,您可以透過執行以下命令來確保supervisor正在運行:
sudo systemctl status supervisor
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 訊號後,該指令將退出循環並完成。然後,主管將再次啟動。
我們已經學會如何使用supervisor來保持命令運行而無需使用crontab。當 crontab 啟動的進程可能重疊並導致資料損壞時,這會很有用。
在我寫的上一本書中,我展示瞭如何使用 Supervisor 來保持 symfony Messenger Worker 的運作。如果您想了解更多信息,可以在這裡找到這本書:使用 PHP 和 Symfony 框架構建面向操作的 Api:分步指南
以上是使用 Supervisor 處理 Symfony 指令執行的詳細內容。更多資訊請關注PHP中文網其他相關文章!