デーモンプロセスとしてphpスクリプトを実行する必要があります(指示を待って作業を行います)。命令が到着するとすぐにアクションを実行する必要があるため、cronジョブはそれを行いません。メモリ管理の問題のため、PHPは実際にはデーモンプロセスに最適なオプションではありませんが、さまざまな理由により、この場合PHPを使用する必要があります。デーモンと呼ばれるlibslackのツールに出会いました( http://libslack.org/daemon )デーモンプロセスの管理に役立つようですが、過去5年間に更新はありませんでした。だから、私の場合に適した他の選択肢を知っているのだろうか。どんな情報でも大歓迎です。
を使用して、コマンドライン(つまりbash)からphpスクリプトを開始できます。
Nohup php myscript.php &
&
は、プロセスをバックグラウンドに配置します。
編集:
はい、いくつかの欠点がありますが、制御することはできませんか?それはただ間違っています。
単純なkill processid
で停止します。そして、それは依然として最良かつ最も簡単なソリューションです。
別のオプションは pstart を使用することです。もともとは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 に大いに感謝します。ここでこのテクニックを学びました。
新しい systemd を使用すると、サービスを作成できます。
/etc/systemd/system/
にファイルまたは symlink を作成する必要があります。 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回実行する必要がある場合、直接PHPの代わりに、シェルまたはbashスクリプトを使用して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
これらのオプションを選択した場合、 KillMode を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」を実行する必要がありますが、変更しないと、必要なときに警告が表示されます。
可能であれば、 NIX環境での高度なプログラミング のコピーを取得します。第13章全体は、デーモンプログラミングに専念しています。例はCですが、必要なすべての関数はPHP(基本的に pcntl および posix 拡張機能)にラッパーを持っています。
いくつかの言葉で-デーモンの作成(これは* nixベースのOS-esでのみ可能です-Windowsはサービスを使用します)は次のようになります。
umask(0)
を呼び出して、権限の問題を防ぎます。fork()
で、親を終了します。setsid()
を呼び出します。SIGHUP
(通常これは無視されるか、デーモンに構成を再ロードするように通知するために使用されます)およびSIGTERM
(プロセスに正常に終了するよう指示する)の信号処理をセットアップします。fork()
を再度実行し、親を終了します。chdir()
で現在の作業ディレクトリを変更します。fclose()
stdin
、stdout
、およびstderr
で、それらに書き込みを行いません。正しい方法は、それらを/dev/null
またはファイルにリダイレクトすることですが、PHPでそれを行う方法が見つかりませんでした。デーモンを起動してシェルを使用してリダイレクトする場合は可能です(その方法を自分で確認する必要がありますが、わかりません:)。また、PHPを使用しているため、PHP 5.3より前のPHPガベージコレクターにはこれらの参照を収集する方法がなく、プロセスがメモリリークするため、循環参照に注意してください、最終的にクラッシュするまで。
多数のPHPデーモンを実行しています。
PHPはこれを行うのに最適な(または優れた)言語ではありませんが、デーモンはWebに面するコンポーネントとコードを共有するため、全体としては良いソリューションです。
これにはdaemontoolsを使用します。スマートで、清潔で、信頼性があります。実際、すべてのデーモンの実行に使用します。
これは http://cr.yp.to/daemontools.html で確認できます。
編集:機能のクイックリスト。
あなたはできる
Nohup
を使用します。screen
を使用し、PHPプログラムをその内部で通常のプロセスとして実行します。これにより、Nohup
を使用するよりも多くの制御が可能になります。最も簡単な方法(私の意見では画面)をお勧めします。さらに機能や機能が必要な場合は、より複雑な方法に移行します。
この問題を解決する方法は複数あります。
詳細はわかりませんが、おそらくPHPプロセスをトリガーする別の方法があります。たとえば、SQLデータベースのイベントに基づいてコードを実行する必要がある場合は、スクリプトを実行するトリガーを設定できます。これはPostgreSQLで簡単に実行できます: http://www.postgresql.org/docs/current/static/external-pl.html .
正直なところ、Nohupを使用してDamonプロセスを作成するのが最善の策だと思います。 Nohupを使用すると、ユーザーがログアウトした後でもコマンドの実行を継続できます。
Nohup php myscript.php &
ただし、非常に深刻な問題があります。 PHPのメモリマネージャーは完全なゴミであると言ったように、スクリプトは数秒間しか実行されずに存在するという前提で構築されました。 PHPスクリプトは、数日後にGIGABYTESのメモリを使用し始めます。また、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つだけ実行されていることを確認できます。
幸運を!
Kevin van Zonneveld これに関する非常に詳細な記事を書いた 、彼の例では System_Daemon
PEAR package (最後のリリース2009-09-02の日付)。
チェックアウト https://github.com/shaneharter/PHP-Daemon
これは、オブジェクト指向のデーモンライブラリです。ロギングやエラー回復などのサポートが組み込まれており、バックグラウンドワーカーの作成もサポートされています。
最近、PHPスクリプトをデーモンとして実行する問題に対するクロスプラットフォームソリューション(Windows、Mac、Linux)が必要になりました。独自のC++ベースのソリューションを作成し、バイナリを作成することで問題を解決しました。
https://github.com/cubiclesoft/service-manager/
Linux(sysvinit経由)を完全にサポートしますが、Windows NTサービスとMac OSXも起動しました。
Linuxだけが必要な場合は、ここで紹介する他のいくつかのソリューションが十分に機能し、フレーバーにもよります。最近はUpstartとsystemdもあり、sysvinitスクリプトへのフォールバックがあります。しかし、PHPを使用するポイントの半分は、本質的にクロスプラットフォームであるということです。そのため、この言語で書かれたコードは、どこでもそのまま動作する可能性が非常に高くなります。特定の外部ネイティブOSレベルの側面がシステムサービスなどの状況に入ると、欠陥が現れ始めますが、ほとんどのスクリプト言語ではこの問題が発生します。
ここで誰かがPHPユーザーランドで提案したようにシグナルをキャッチしようとするのは良い考えではありません。 pcntl_signal()
のドキュメントを注意深く読むと、PHPがプロセスではめったに見られない何かのサイクルを噛むかなり不快なメソッド(具体的には 'ticks')を使用してシグナルを処理することがすぐにわかります。 (つまり、シグナル)。 PHPでのシグナル処理もPOSIXプラットフォームでかろうじてしか利用できず、サポートはPHPのバージョンによって異なります。最初はまともな解決策のように聞こえますが、真に有用であるとは言えません。
PHPは、時間の経過とともにメモリリークの問題も改善しています。まだ注意する必要があります(DOM XMLパーサーはまだリークする傾向があります)が、最近では暴走プロセスはほとんど見られず、PHPバグトラッカーは昔の日と比べてかなり静かです。
他の人がすでに述べたように、PHPをデーモンとして実行するのは非常に簡単で、1行のコマンドを使用して実行できます。しかし、実際の問題は、それを実行し、管理することです。私はかなり前に同じ問題を抱えており、すでに利用可能なソリューションはたくさんありますが、それらの多くは多くの依存関係を持っているか、使用が難しく、基本的な使用には適していません。 PHP cliスクリプトを含む任意のプロセス/アプリケーションを管理できるシェルスクリプトを作成しました。アプリケーションを起動するcronjobとして設定でき、アプリケーションを含めて管理します。同じcronjobなどを介して再度実行された場合、アプリが実行されているかどうかを確認し、実行されている場合は単に終了し、前のインスタンスがアプリケーションの管理を続行できるようにします。
Githubにアップロードしましたので、お気軽に使用してください: https://github.com/sinasalek/EasyDeamonizer
EasyDeamonizer
アプリケーションを監視するだけです(起動、再起動、ログ、監視など)。アプリケーションが適切に実行されていることを確認する汎用スクリプト。意図的にpid/lockファイルのプロセス名instreadを使用して、すべての副作用を防ぎ、スクリプトを可能な限りシンプルで攪拌し続けるようにします。そのため、EasyDaemonizer自体が再起動されても常に動作します。特徴
拡張Emil Ivaov answer、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
呼び出しは、標準のIOを/dev/null
に設定します。
これをRob Aley-PHPウェブの向こう側の本から読みました。
シンプルなphp-daemonを作成してデプロイしました。コードはここでオンラインです
https://github.com/jmullee/PhpUnixDaemon
機能:特権のドロップ、シグナル処理、ロギング
キューハンドラーで使用しました(ユースケース:ページ生成phpを待機させずに、Webページから長時間の操作をトリガーします。つまり、非同期操作を起動します) https://github.com/jmullee/ PhpIPCMessageQueue
ここでpm2を確認できます http://pm2.keymetrics.io/
対処するphpスクリプトにworker.shなどのsshファイルを作成します。
worker.sh
php /path/myscript.php
デーモン開始
pm2 start worker.sh
乾杯、それだけです。