phpスクリプトをデーモンプロセスとして実行する


154

私は、phpスクリプトをデーモンプロセスとして実行する必要があります(指示を待って何かを行う)。命令が到着したらすぐにアクションを実行する必要があるため、cronジョブはそれを行いません。メモリ管理の問題により、PHPがデーモンプロセスに最適なオプションではないことはわかっていますが、この場合、PHPを使用する必要があるさまざまな理由があります。デーモン(http://libslack.org/daemon)と呼ばれるlibslackのツールに出会いました。デーモンプロセスを管理するのに役立つようですが、過去5年間更新されていないので、いくつか知っていますか私の場合に適した他の選択肢。どんな情報でも大歓迎です。


2
私の答えを確認してください。感謝
Henrik P. Hessel


1
私はこの投稿gonzalo123.com/2010/05/23/…に遭遇しました。
Teson 2014

回答:


167

次のコマンドを使用して、コマンドライン(bash)からphpスクリプトを開始できます。

nohup php myscript.php &

&バックグラウンドでプロセスを置きます。

編集:
はい、いくつかの欠点がありますが、制御することはできませんか?それは間違っています。
シンプルkill processidはそれを止めます。そして、それは依然として最良かつ最も簡単なソリューションです。


端末が存在する場合、プロセスは終了しません。これが、「nohup」コマンドが存在する理由です。私は何年もの間、このようなすべてのサーバーでPHPスクリプトをデーモンとして使用しています。より良い解決策があるかもしれませんが、これが最も速い解決策です。
CDR 2010年

27
デーモンが失敗しても再起動しません。また、デーモンを簡単に管理する方法はありません。
Phil Wallach、2010年

6
ここで述べたことに同意します-これは悪い解決策です。いくつかの理由でinitスクリプトを作成する必要があります。1)起動時にinitスクリプトが自動的に起動されます。2)start / stop / restartコマンドでデーモンを管理できます。ここでservefaultからの例です:serverfault.com/questions/229759/...
サル

1
こんにちは...それは私nohup&は思われ、同じことを行います:シェルの現在のインスタンスから起動されたプロセスを切り離します。なぜ両方必要なのですか?ただやることはできませんphp myscript.php &nohup myscript.php?ありがとう
nourdine 2014年

1
スクリプトが標準出力に(経由でエコーまたはのvar_dump)を書き込んなら、あなたは、このようなログファイルを使用してこの情報をキャッチすることができます:nohup php myscript.php > myscript.log &
ミーシャ

167

別のオプションは、Upstartを使用することです。もともとはUbuntu用に開発されました(デフォルトでパッケージ化されています)が、すべてのLinuxディストリビューションに適合することを目的としています。

このアプローチは、システムの起動時にデーモンを自動的に開始し、スクリプトの完了時に再起動するという点で、Supervisordおよびdaemontoolsに似ています。

設定方法:

で新しいスクリプトファイルを作成します/etc/init/myphpworker.conf。次に例を示します。

# Info
description "My PHP Worker"
author      "Jonathan"

# Events
start on startup
stop on shutdown

# Automatically respawn
respawn
respawn limit 20 5

# Run the script!
# Note, in this example, if your PHP script returns
# the string "ERROR", the daemon will stop itself.
script
    [ $(exec /usr/bin/php -f /path/to/your/script.php) = 'ERROR' ] && ( stop; exit 1; )
end script

デーモンの開始と停止:

sudo service myphpworker start
sudo service myphpworker stop

デーモンが実行されているかどうかを確認します。

sudo service myphpworker status

ありがとう

このテクニックを学んだKevin van Zonneveldに感謝します。


2
これを愛する。ただ不思議に思っています、複数の同時ワーカーを持つことは可能ですか?私はただ一人の労働者がもう十分ではないという問題を抱えています。
マヌエル

1
これはシステムの起動時に自動的に実行されますか?
14

2
sudo "service myphpworker start"が機能しませんでした。私は「sudo start myphpworker」を使用しましたが、完全に機能します
Matt Sich

3
@Pradeeptaそれは投稿にエラーがあるためです-私は正確に何が(そしてこれをテストしていません)わかりませんが、私はsudo service myphpworker start/stop/statusそれが/etc/init.dupstartサービスではないサービスでのみ機能すると思います。@ matt-sichは正しい構文を明らかにしたようです。別のオプションは、バックグラウンド処理とデーモン化を可能にするGearmanまたはResqueを使用することです。
ckm 2015

3
Ubuntu自体は、upstartの代わりにsystemdを使用するように移行しています:zdnet.com/article/after-linux-civil-war-ubuntu-to-adopt-systemd
Kzqai

72

新しい systemdを使用すると、サービスを作成できます。

あなたは、ファイルまたは作成する必要があります。シンボリックリンクでは /etc/systemd/system/例えば、。myphpdaemon.serviceと次のようなコンテンツを配置すると、myphpdaemonがサービスの名前になります。

[Unit]
Description=My PHP Daemon Service
#May your script needs MySQL or other services to run, eg. MySQL Memcached
Requires=mysqld.service memcached.service 
After=mysqld.service memcached.service

[Service]
User=root
Type=simple
TimeoutSec=0
PIDFile=/var/run/myphpdaemon.pid
ExecStart=/usr/bin/php -f /srv/www/myphpdaemon.php arg1 arg2> /dev/null 2>/dev/null
#ExecStop=/bin/kill -HUP $MAINPID #It's the default you can change whats happens on stop command
#ExecReload=/bin/kill -HUP $MAINPID
KillMode=process

Restart=on-failure
RestartSec=42s

StandardOutput=null #If you don't want to make toms of logs you can set it null if you sent a file or some other options it will send all php output to this one.
StandardError=/var/log/myphpdaemon.log
[Install]
WantedBy=default.target

コマンドを使用して、サービスの開始、ステータスの取得、再起動、停止を行うことができます

systemctl <start|status|restart|stop|enable> myphpdaemon

PHPスクリプトには、実行を継続するための一種の「ループ」が必要です。

<?php
gc_enable();//
while (!connection_aborted() || PHP_SAPI == "cli") {

  //Code Logic

  //sleep and usleep could be useful
    if (PHP_SAPI == "cli") {
        if (rand(5, 100) % 5 == 0) {
            gc_collect_cycles(); //Forces collection of any existing garbage cycles
        }
    }
}

作業例:

[Unit]
Description=PHP APP Sync Service
Requires=mysqld.service memcached.service
After=mysqld.service memcached.service

[Service]
User=root
Type=simple
TimeoutSec=0
PIDFile=/var/run/php_app_sync.pid
ExecStart=/bin/sh -c '/usr/bin/php -f /var/www/app/private/server/cron/app_sync.php  2>&1 > /var/log/app_sync.log'
KillMode=mixed

Restart=on-failure
RestartSec=42s

[Install]
WantedBy=default.target

PHPルーチンを(ダイジェストのように)サイクルで1回実行する必要がある場合は、シェルまたはbashスクリプトを使用して、PHPの代わりに直接systemdサービスファイルを呼び出す必要があります。次に例を示します。

#!/usr/bin/env bash
script_path="/app/services/"

while [ : ]
do
#    clear
    php -f "$script_path"${1}".php" fixedparameter ${2}  > /dev/null 2>/dev/null
    sleep 1
done

これらのオプションを選択した場合、KillModeprocessesに変更しmixed、bash(main)およびPHP(child)を強制終了する必要があります。

ExecStart=/app/phpservice/runner.sh phpfile parameter  > /dev/null 2>/dev/null
KillMode=process

This method also is effective if you're facing a memory leak.

注: "myphpdaemon.service"を変更するたびに、 `systemctl daemon-reload 'を実行する必要がありますが、実行しない場合は心配する必要があります。


7
過小評価された答え。あなたは私の+1を持っています。
Gergely Lukacsy 2017

2
驚くばかり。これはこのページに埋め込むべきではないので、私たちも回答をこころに込めたいと思います。
ジャスティン

1
あなたはsystemctl status <your_service_name> -l出力をチェックするべきです、それはあなたに何が起こっているかの手掛かりを与えます。
LeonanCarvalho 2018

1
@LeandroTupone MySQLとMemcachedは、サービスの依存関係をどのように使用する必要があるかを示すデモでした。
LeonanCarvalho

3
これは、実際にそれが今2019年だと見て受け入れ答えを交換する必要があります
スパイス

47

UNIX環境での高度なプログラミングのコピーを入手できる場合。第13章全体は、デーモンプログラミングに専念しています。例はCですが、必要なすべての関数にはPHPのラッパーがあります(基本的にはpcntlおよびposix拡張機能)。

一言で言えば-デーモンの記述(これは* nixベースのOS-esでのみ可能です-Windowsはサービスを使用します)は次のようになります。

  1. umask(0)許可の問題を防ぐために電話してください。
  2. fork() 親の出口があります。
  3. を呼び出しsetsid()ます。
  4. SIGHUP(通常、これは無視されるか、デーモンに構成を再ロードするようシグナルを送るために使用されます)およびSIGTERM(プロセスに正常に終了するように指示する)のセットアップシグナル処理
  5. fork() 再び、親の出口を持っています。
  6. 現在の作業ディレクトリをで変更しchdir()ます。
  7. fclose() stdinstdoutそしてstderrそれらに書いてはいけません。正しい方法は、いずれか/dev/nullまたはファイルにそれらをリダイレクトすることですが、PHPでそれを行う方法を見つけることができませんでした。デーモンを起動して、シェルを使用してそれらをリダイレクトすることは可能です(その方法を自分で見つける必要がありますが、わかりません:)。
  8. 仕事をしなさい!

また、PHPを使用しているため、循環参照には注意してください。PHP5.3より前のPHPガベージコレクターでは、これらの参照を収集する方法がなく、プロセスが最終的にクラッシュするまでメモリリークが発生します。


1
情報をありがとう。libslackのデーモンプログラムは、あなたが述べたように、すべての準備作業をほとんど行っているようです。今のところ、他の良い代替案が見つかるまでそれを使い続けると思います。
Beier

1
この投稿が見つかりました。標準入力などを閉じることができないだらしない古いアプリケーションにコピーして貼り付けると予想されるコードは失望しました。:p
ThiefMaster 2013年

1
なぜ(5)再びfork()するのですか?
TheFox 2014

私のために働いた-素晴らしい仕事!
ゴータムシャルマ2015

なぜ二度フォークするのかと尋ねる将来の読者のために:stackoverflow.com/questions/881388/…-TL ; DR:ゾンビを防ぎます。
ゲディパンク2015年

24

多数のPHPデーモンを実行しています。

PHPはこれを行うのに最適な(または優れた)言語ではないが、デーモンはコードをWeb向けコンポーネントと共有するので、全体として私たちにとっては良いソリューションです。

これにはdaemontoolsを使用します。スマートでクリーンで信頼性が高いです。実際、すべてのデーモンを実行するために使用しています。

これはhttp://cr.yp.to/daemontools.htmlで確認できます

編集:機能のクイックリスト。

  • 再起動時にデーモンを自動的に起動します
  • 障害時にdameonを自動的に再起動します
  • ロギングはロールオーバーとプルーニングを含めて自動的に処理されます
  • 管理インターフェース:「svc」および「svstat」
  • UNIXフレンドリー(おそらく誰にとってもプラスではない)

リポジトリからもインストール可能です。
Kzqai 2017年

14

あなたはできる

  1. nohupヘンリックの提案どおりに使用します。
  2. screenその内部で通常のプロセスとしてPHPプログラムを使用して実行します。これにより、を使用するよりも詳細に制御できますnohup
  3. http://supervisord.org/などのデーモン化機能を使用します(Pythonで記述されていますが、コマンドラインプログラムをデーモン化して、リモートコントロールで管理することができます)。
  4. Emilが提案したように独自のデーモン化ラッパーを記述しますが、それはIMOのやりすぎです。

最も簡単な方法(私の意見では画面)をお勧めします。機能や機能をもっと必要な場合は、より複雑な方法に移行してください。


同様の監視構成を提供できますか?
Alix Axel

11

この問題を解決する方法は複数あります。

詳細はわかりませんが、PHPプロセスをトリガーする別の方法があるかもしれません。たとえば、SQLデータベースのイベントに基づいてコードを実行する必要がある場合は、スクリプトを実行するトリガーを設定できます。これはPostgreSQLで本当に簡単です:http : //www.postgresql.org/docs/current/static/external-pl.html

正直なところ、私はあなたの最善の策はnohupを使用してデーモンプロセスを作成することだと思います。nohupを使用すると、ユーザーがログアウトした後でもコマンドを実行し続けることができます。

nohup php myscript.php &

しかし、非常に深刻な問題があります。PHPのメモリマネージャは完全にガベージであるとおっしゃいましたが、スクリプトは数秒間しか実行されずに存在することを前提に構築されています。PHPスクリプトは、数日後にギガバイトのメモリの使用を開始します。また、12時間ごとまたは24時間ごとに実行するcronスクリプトを作成して、次のようにphpスクリプトを強制終了して再起動する必要もあります。

killall -3 php
nohup php myscript.php &

しかし、スクリプトがジョブの途中にあった場合はどうでしょうか。よくkill -3は割り込みです。CLIでctrl + cを実行するのと同じです。PHPスクリプトが正常PHPのPCNTLライブラリを使用して、この割り込みと終了をキャッチすることができます。http://php.oregonstate.edu/manual/en/function.pcntl-signal.php

次に例を示します。

function clean_up() {
  GLOBAL $lock;
  mysql_close();
  fclose($lock)
  exit();
}
pcntl_signal(SIGINT, 'clean_up');

$ lockの背後にある考え方は、PHPスクリプトがfopen( "file"、 "w");でファイルを開くことができるということです。ファイルの書き込みロックを設定できるプロセスは1つだけなので、これを使用すると、PHPスクリプトのコピーが1つだけ実行されていることを確認できます。

幸運を!




3

最近、PHPスクリプトをデーモンとして実行する問題に対するクロスプラットフォームソリューション(Windows、Mac、およびLinux)が必要になりました。私は自分のC ++ベースのソリューションを作成してバイナリを作成することで問題を解決しました:

https://github.com/cubiclesoft/service-manager/

Linux(sysvinitを使用)の完全サポート、およびWindows NTサービスとMac OSXの起動。

Linuxだけが必要な場合は、ここで紹介する他のいくつかのソリューションで十分に機能します。最近ではsysvinitスクリプトにフォールバックしているUpstartとsystemdもあります。しかし、PHPを使用するポイントの半分は、PHPが本質的にクロスプラットフォームであることです。そのため、この言語で記述されたコードは、あらゆる場所でそのまま機能する可能性がかなり高くなります。システムサービスなどの特定の外部ネイティブOSレベルの側面が問題になってくると、欠陥が現れ始めますが、ほとんどのスクリプト言語でこの問題が発生します。

ここでPHPユーザーランドで提案されているようにシグナルをキャッチしようとするのは良い考えではありません。ドキュメンテーションをpcntl_signal()注意深く読んでください。PHPは、プロセスではめったに見られないもの(つまり、シグナル)のサイクルを大量に消費する、かなり不愉快なメソッド(具体的には、「ティック」)を使用してシグナルを処理することをすぐに学びます。PHPでの信号処理もPOSIXプラットフォームでのみ利用可能であり、サポートはPHPのバージョンによって異なります。最初はまともなソリューションのように聞こえますが、それは本当に有用であるにはほど遠いです。

PHPは、時間の経過とともにメモリリークの問題についても改善しています。あなたはまだ注意する必要があります(DOM XMLパーサーはまだリークする傾向があります)が、最近は暴走プロセスを目にすることはめったになく、PHPバグトラッカーは昔の時代と比べるとかなり静かです。


1

他の人がすでに述べたように、PHPをデーモンとして実行するのは非常に簡単で、1行のコマンドを使用して実行できます。しかし、実際の問題は、それを実行し続け、管理することです。私はかなり前に同じ問題を抱えていましたが、すでに利用可能なソリューションはたくさんありますが、それらのほとんどは依存関係がたくさんあるか、使用が難しく、基本的な使用には適していません。PHP cliスクリプトを含む任意のプロセス/アプリケーションを管理できるシェルスクリプトを書きました。アプリケーションを開始するためのcronjobとして設定でき、アプリケーションを格納して管理します。たとえば同じcronjobを介して再度実行された場合は、アプリが実行されているかどうかを確認し、実行されている場合は単に終了して、前のインスタンスがアプリケーションの管理を続行できるようにします。

私はそれをgithubにアップロードしました、自由に使ってくださいhttps : //github.com/sinasalek/EasyDeamonizer

EasyDeamonizer

アプリケーションを監視するだけです(起動、再起動、ログ、監視など)。アプリケーションが適切に実行されていることを確認するための汎用スクリプト。意図的にpid / lockファイルのプロセス名instreadを使用して、そのすべての副作用を防ぎ、スクリプトをできるだけ単純で撹拌的な状態に保つため、EasyDaemonizer自体が再起動された場合でも常に機能します。特徴

  • アプリケーションを開始し、オプションで開始ごとにカスタマイズされた遅延を開始します
  • 1つのインスタンスのみが実行されていることを確認します
  • CPU使用率を監視し、定義されたしきい値に達したときにアプリを自動的に再起動します
  • EasyDeamonizerがcron経由で実行されるように設定し、何らかの理由で停止された場合に再実行
  • その活動を記録します

1

Emil Ivaovの答えを拡張して、次のようにして、phpでSTDIN、STDOUT、およびSTDERRORを閉じることができます。

if (!fclose(STDIN)) {
    exit("Could not close STDIN");
}

if (!fclose(STDOUT)) {
    exit("Could not close STDOUT");
}

if (!fclose(STDERR)) {
    exit("Could not close STDERR");
}

$STDIN = fopen('/dev/null', 'r');
$STDOUT = fopen('/dev/null', 'w');
$STDERR = fopen('/var/log/our_error.log', 'wb');

基本的に、PHPに書き込む場所がないように、標準ストリームを閉じます。次のfopen呼び出しは、標準入出力をに設定し/dev/nullます。

私はこの本をRob Aleyの本から読みました-Webを超えたPHP


0

簡単なphp-daemonを作成してデプロイしました。コードはこちらからオンラインでご覧いただけます

https://github.com/jmullee/PhpUnixDaemon

機能:特権の削除、信号処理、ロギング

私はそれをキューハンドラーで使用しました(使用例:ページ生成phpを待機させることなく、Webページから長い操作をトリガーする、つまり非同期操作を起動する) https://github.com/jmullee/PhpIPCMessageQueue


0

あなたはここにPM2チェックすることができ、あるhttp://pm2.keymetrics.io/

処理するphpスクリプトに、worker.shなどのsshファイルを作成します。

worker.sh

php /path/myscript.php

デーモン起動

pm2 start worker.sh

乾杯、それだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.