运行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使用服务)是这样的:

  1. 调用umask(0)来防止许可问题。
  2. fork()并有父级出口。
  3. 调用setsid()
  4. SIGHUP设置信号处理(通常这被忽略或者用来指示守护进程重新加载它的配置)和SIGTERM (告诉进程正常退出)。
  5. fork() ,并有父级出口。
  6. 使用chdir()更改当前的工作目录。
  7. fclose() stdinstdoutstderr ,不写信给他们。 正确的方法是将它们重定向到/dev/null或一个文件,但是我找不到在PHP中执行它的方法。 当你启动守护进程使用shell重定向它时,你可能会发现自己该怎么做,我不知道。
  8. 做你的工作!

此外,由于您使用的是PHP,所以请谨慎使用循环引用,因为PHP 5.3之前的PHP垃圾回收器无法收集这些引用,并且该进程将会内存泄漏,直到最终崩溃。

我运行了大量的PHP守护进程。

我同意你的看法,PHP并不是最好的(甚至是好的)语言,但是守护进程与面向网络的组件共享代码,所以总的来说这对我们来说是一个很好的解决方案。

我们使用daemontools来做到这一点。 它聪明,干净可靠。 实际上,我们使用它来运行我们所有的守护进程。

你可以在http://cr.yp.to/daemontools.html查看。;

编辑:功能的快速列表。

  • 自动启动守护进程重新启动
  • 在失败时自动重启dameon
  • 记录是为您处理的,包括翻转和修剪
  • 管理界面:'svc'和'svstat'
  • UNIX友好(不是每个人都加)

您可以

  1. Henrik建议使用nohup
  2. 使用screen并运行你的PHP程序作为一个普通的进程。 这比使用nohup给你更多的控制。
  3. 使用像http://supervisord.org/这样的守护进程(它是用Python编写的,但可以守护任何命令行程序并给你一个远程控制来管理它)。;
  4. 写你自己的守护进程包装像埃米尔建议,但它是过度的国际海事组织。

我建议最简单的方法(在我看来,屏幕),然后如果你想更多的功能或功能,移动到更复杂的方法。

有多种方法可以解决这个问题。

我不知道细节,但也许有另一种方法来触发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