运行php脚本作为守护进程
我需要运行一个PHP脚本作为守护进程(等待指示和做的东西)。 cron的工作不会为我做,因为行动需要尽快采取指令到达。 我知道由于内存管理问题,PHP并不是守护进程的最佳选择,但由于各种原因,我必须在这种情况下使用PHP。 我遇到了一个名为Daemon的libslack工具( http://libslack.org/daemon ),它似乎帮助我管理守护进程,但在过去的5年里没有任何更新,所以我不知道你是否知道其他选择适合我的情况。 任何信息将非常感激。
你可以通过使用命令行(即bash)来启动你的php脚本
nohup php myscript.php &
&
把你的过程放在后台。
编辑:
是的,有一些缺点,但不可能控制? 这是错的。
一个简单的kill processid
会阻止它。 而且这仍然是最好和最简单的解决方案。
另一个选择是使用Upstart 。 它最初是为Ubuntu开发的(默认情况下与它一起打包),但是打算适用于所有Linux发行版。
这种方法类似于Supervisord和守护进程,它在系统启动时自动启动守护进程,并在脚本完成时重新启动。
如何设置:
在/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 ,我从中学到了这个技巧。
如果可以的话 – 在UNIX环境中获取高级编程的副本。 整个第13章致力于守护进程编程。 例子是在C中,但所有你需要的函数在PHP中包装(基本上pcntl和posix扩展)。
简而言之 – 编写一个守护进程(这只适用于基于* nix的操作系统 – Windows使用服务)是这样的:
- 调用
umask(0)
来防止许可问题。 -
fork()
并有父级出口。 - 调用
setsid()
。 -
SIGHUP
设置信号处理(通常这被忽略或者用来指示守护进程重新加载它的配置)和SIGTERM
(告诉进程正常退出)。 -
fork()
,并有父级出口。 - 使用
chdir()
更改当前的工作目录。 -
fclose()
stdin
,stdout
和stderr
,不写信给他们。 正确的方法是将它们重定向到/dev/null
或一个文件,但是我找不到在PHP中执行它的方法。 当你启动守护进程使用shell重定向它时,你可能会发现自己该怎么做,我不知道。 - 做你的工作!
此外,由于您使用的是PHP,所以请谨慎使用循环引用,因为PHP 5.3之前的PHP垃圾回收器无法收集这些引用,并且该进程将会内存泄漏,直到最终崩溃。
我运行了大量的PHP守护进程。
我同意你的看法,PHP并不是最好的(甚至是好的)语言,但是守护进程与面向网络的组件共享代码,所以总的来说这对我们来说是一个很好的解决方案。
我们使用daemontools来做到这一点。 它聪明,干净可靠。 实际上,我们使用它来运行我们所有的守护进程。
你可以在http://cr.yp.to/daemontools.html查看。;
编辑:功能的快速列表。
- 自动启动守护进程重新启动
- 在失败时自动重启dameon
- 记录是为您处理的,包括翻转和修剪
- 管理界面:'svc'和'svstat'
- UNIX友好(不是每个人都加)
您可以
- Henrik建议使用
nohup
。 - 使用
screen
并运行你的PHP程序作为一个普通的进程。 这比使用nohup
给你更多的控制。 - 使用像http://supervisord.org/这样的守护进程(它是用Python编写的,但可以守护任何命令行程序并给你一个远程控制来管理它)。;
- 写你自己的守护进程包装像埃米尔建议,但它是过度的国际海事组织。
我建议最简单的方法(在我看来,屏幕),然后如果你想更多的功能或功能,移动到更复杂的方法。
有多种方法可以解决这个问题。
我不知道细节,但也许有另一种方法来触发PHP过程。 例如,如果您需要根据SQL数据库中的事件运行代码,则可以设置触发器来执行脚本。 这在PostgreSQL下很容易实现: http : //www.postgresql.org/docs/current/static/external-pl.html 。
老实说,我认为你最好的选择是用nohup创建一个Damon进程。 nohup允许命令在用户注销后继续执行:
nohup php myscript.php &
然而有一个非常严重的问题。 正如你所说PHP的内存管理器是完整的垃圾,它建立在一个脚本只执行几秒钟然后存在的假设。 短短几天之后,您的PHP脚本就会开始使用内存的GIGABYTES。 你还必须创建一个cron脚本,每12或24小时运行一次,杀死并重新生成你的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脚本的副本正在运行。
祝你好运!
用新的systemd你可以创建一个服务(在基于rhel的linux上)。
您必须在/etc/systemd/system/
创建一个文件,例如。 myphpdaemon.service并放置一个这样的内容,myphpdaemon将是服务的名称:
[Unit] Description=Your PHP Daemon Service #Requires=mysqld.service memcached.service #May your script needs mysql or other services to run. #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 #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 #Restart=on-failure #RestartPreventExitStatus=1 #PrivateTmp=false 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=process Restart=on-failure RestartSec=42s [Install] WantedBy=default.target
注意:每次更改“myphpdaemon.service”时,都必须运行`systemctl daemon-reload',但是如果不这样做会担心,会在需要时提示。
Kevin van Zonneveld 写了一篇非常不错的详细文章 ,在他的例子中他使用了System_Daemon
PEAR软件包 (2009-09-02的最后发布日期)。
看看https://github.com/shaneharter/PHP-Daemon
这是一个面向对象的守护进程库。 它内置了对日志和错误恢复等内容的支持,并且支持创建后台工作者。
我最近需要一个跨平台的解决方案(Windows,Mac和Linux)来处理PHP脚本作为守护进程的问题。 我通过编写自己的基于C ++的解决方案并制作二进制文件来解决问题:
https://github.com/cubiclesoft/service-manager/
完全支持Linux(通过sysvinit),而且还支持Windows NT服务和Mac OSX。
如果您只需要Linux,那么这里介绍的其他一些解决方案就可以很好地工作,具体取决于风格。 现在还有Upstart和systemd,它们具有对sysvinit脚本的回退功能。 但是使用PHP的一半重点在于它是跨平台的,所以用这种语言编写的代码在现在到处都有很好的工作机会。 当某些外部本地操作系统级别的方面进入系统服务之类时,缺陷就开始显现出来,但是大多数脚本语言会遇到这个问题。
试图捕捉信号在这里建议在PHP用户空间不是一个好主意。 请仔细阅读pcntl_signal()
上的文档,您将很快得知PHP使用一些相当不愉快的方法(特别是“嘀嗒”)处理信号,这些方法会为进程(即信号)罕见的东西嚼碎一堆循环。 PHP中的信号处理在POSIX平台上也几乎不可用,并且支持根据PHP的版本而有所不同。 它最初听起来像一个体面的解决方案,但它没有真正有用的。
随着时间的推移,PHP对内存泄漏问题也越来越好。 你仍然要小心(DOM XML解析器仍然会泄漏),但是现在我很少看到失控的进程,而PHP错误跟踪器相对于以前的日子来说是非常安静的。
正如其他人已经提到的那样,将PHP作为守护进程运行是非常简单的,可以使用一行命令来完成。 但实际的问题是保持运行和管理它。 一段时间以前,我也遇到了同样的问题,虽然现在已经有很多解决方案了,但是其中大部分都有很多的依赖关系,或者很难使用,不适合基本的用法。 我写了一个shell脚本,可以管理任何流程/应用程序,包括PHP cli脚本。 它可以设置为一个cronjob来启动应用程序,并将包含应用程序并进行管理。 如果它再次执行,例如通过相同的cronjob,它检查应用程序是否正在运行,如果它确实退出,并让它的前一个实例继续管理应用程序。
我把它上传到github,随意使用它: https : //github.com/sinasalek/EasyDeamonizer
EasyDeamonizer
只需监视您的应用程序(启动,重新启动,日志,监视器等)。 一个通用脚本,以确保您的应用程序保持正常运行。 有意地,它使用pid / lock文件的进程名称instread来防止其所有的副作用,并保持脚本尽可能简单并且尽可能的简单,所以即使在EasyDaemonizer本身重新启动的情况下也是如此。 特征
- 启动应用程序并为每次启动选择一个自定义延迟
- 确保只有一个实例正在运行
- 监视CPU使用情况,并在达到设定的阈值时自动重新启动应用程序
- 如果由于某种原因暂停,将EasyDeamonizer设置为通过cron运行再次运行
- 记录其活动
我编写并部署了一个简单的php-daemon,代码在这里
https://github.com/jmullee/PhpUnixDaemon
特点:特权下降,信号处理,日志记录
我在一个队列处理程序中使用它(用例:从网页触发一个冗长的操作,而不会使页面生成的PHP等待,即启动一个异步操作) https://github.com/jmullee/PhpIPCMessageQueue