我需要运行一个PHP脚本作为守护进程(等待指令并做一些事情).cron job不会为我做,因为一旦指令到达就需要采取行动.我知道由于内存管理问题,PHP实际上不是守护进程的最佳选择,但由于各种原因,我必须在这种情况下使用PHP.我遇到了libslack的一个名为Daemon(http://libslack.org/daemon)的工具,它似乎可以帮助我管理守护进程,但是在过去的5年中没有任何更新,所以我想知道你是否知道一些其他替代方案适合我的情况.任何信息都将非常感激.
您可以使用命令行(即bash)启动PHP脚本
nohup php myscript.php &
在&
把你的程序在后台运行.
编辑:
是的,有一些缺点,但无法控制?那是错的.
简单kill processid
就会阻止它.它仍然是最好,最简单的解决方案.
另一种选择是使用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,我在那里学习了这项技术.
使用新的 systemd,您可以创建服务(在基于rhel的linux上).
您必须在 ,例如,创建文件或符号链接/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
PHP脚本应该有一种"循环"来继续运行.
工作范例:
[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应该在一个循环中执行一次(比如diggest),你可以使用shell或bash脚本直接调用systemd服务文件而不是PHP,例如:
#!/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(主)和PHP(儿童)被杀害.ExecStart=/app/phpservice/runner.sh phpfile parameter > /dev/null 2>/dev/null KillMode=process注意:每次更改"myphpdaemon.service"时,都必须运行`systemctl daemon-reload',但如果不这样做,请务必担心,需要时会提示.
低估的答案.你有我的+1.
真棒.希望我们能够回答这个问题,因为这不应该埋在这个页面上.
4> Emil Ivanov..:如果可以 - 在UNIX环境中获取高级编程的副本.整个第13章专门用于守护程序编程.示例在C中,但您需要的所有函数都包含PHP中的包装器(基本上是pcntl和posix扩展).
简而言之 - 编写一个守护进程(这只能在基于*nix的OS-es上运行--Windows使用服务)是这样的:
致电
umask(0)
以防止许可问题.
fork()
并让父退出.打电话
setsid()
.设置信号处理
SIGHUP
(通常忽略或用于通知守护进程重新加载其配置)和SIGTERM
(告诉进程正常退出).
fork()
再次并让父退出.使用更改当前工作目录
chdir()
.
fclose()
stdin
,stdout
并且stderr
不要写信给他们.正确的方法是将它们重定向到一个/dev/null
或一个文件,但我找不到在PHP中这样做的方法.当你启动守护进程使用shell重定向它们时,你可能会发现它(你必须自己找出如何做到这一点,我不知道:).做你的工作!
此外,由于您使用的是PHP,因此要小心循环引用,因为在PHP 5.3之前的PHP垃圾收集器无法收集这些引用,并且进程将内存泄漏,直到它最终崩溃.
5> Phil Wallach..:我运行了大量的PHP守护进程.
我同意你的观点,PHP并不是最好的(甚至是好的)语言,但守护进程与面向Web的组件共享代码,所以总体来说它对我们来说是一个很好的解决方案.
我们为此使用daemontools.它聪明,干净,可靠.实际上我们用它来运行我们所有的守护进程.
您可以在http://cr.yp.to/daemontools.html上查看.
编辑:快速功能列表.
重启时自动启动守护程序
失败时自动重启dameon
记录是为您处理的,包括翻转和修剪
管理界面:'svc'和'svstat'
UNIX友好(也许不是每个人的加分)
6> Noufal Ibrah..:您可以
nohup
像Henrik建议的那样使用.使用
screen
并运行PHP程序作为其中的常规过程.这比使用更能控制nohup
.使用像http://supervisord.org/这样的守护进程(它是用Python编写的,但可以对任何命令行程序进行守护,并为您提供远程控制来管理它).
编写自己的守护程序包装,像埃米尔建议,但它是矫枉过正的IMO.
我推荐最简单的方法(在我看来是屏幕)然后如果你想要更多的功能或功能,请转向更复杂的方法.
7> rook..:解决这个问题的方法不止一种.
我不知道具体细节,但也许还有另一种触发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 &但是,如果脚本正在工作中呢?杀-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");打开一个文件.只有一个进程可以对文件进行写锁定,因此使用此方法可以确保只运行PHP脚本的一个副本.
祝好运!
8> Alix Axel..:Kevin van Zonneveld 写了一篇非常详细的文章,在他的例子中他使用了
System_Daemon
PEAR包(最后发布日期为2009-09-02).
9> Shane H..:查看https://github.com/shaneharter/PHP-Daemon
这是一个面向对象的守护程序库.它内置了对日志记录和错误恢复等内容的支持,并且支持创建后台工作程序.