Run php script as daemon process
我需要运行一个PHP脚本作为守护进程(等待指令并做一些事情)。cron作业不会为我做这件事,因为指令一到就需要采取行动。我知道,由于内存管理问题,PHP并不是守护进程的最佳选择,但是由于各种原因,在本例中我必须使用PHP。我遇到了libslack的一个工具,叫做daemon(http://libslack.org/daemon),它似乎可以帮助我管理守护进程,但在过去的5年中没有任何更新,所以我想知道您是否知道适合我的情况的其他替代方法。任何信息都会非常感谢。
通过使用
编辑:是的,有一些缺点,但不可能控制?那是错误的。一个简单的
另一种选择是使用新贵。它最初是为Ubuntu开发的(默认情况下随附在一起),但旨在适用于所有Linux发行版。
这种方法与supervisor和daemontools类似,因为它在系统启动时自动启动守护进程,并在脚本完成时重新显示。
如何设置:在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 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 |
启动和停止守护进程:
1 2 | sudo service myphpworker start sudo service myphpworker stop |
检查您的守护进程是否正在运行:
1 | sudo service myphpworker status |
谢谢
非常感谢凯文·范佐尼菲尔德,在那里我学到了这项技术。
如果可以的话-获取一份Unix环境中高级编程的副本。整个第13章都是关于守护程序编程的。示例在C中,但是您需要的所有函数都有PHP中的包装器(基本上是PCNTL和POSIX扩展)。
用几句话来说——编写一个守护进程(这只在基于*nix的OS ES上可以设置——Windows使用服务)如下所示:
此外,由于您使用的是PHP,因此请注意循环引用,因为在php 5.3之前的php垃圾收集器无法收集这些引用,并且进程将发生内存泄漏,直到最终崩溃。
使用新的systemd,您可以创建一个服务。
您必须在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | [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 |
您将能够使用命令启动、获取状态、重新启动和停止服务。
PHP脚本应该有一种"循环"来继续运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?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 } } } |
工作示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [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,例如:
1 2 3 4 5 6 7 8 9 | #!/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更改为
1 2 | ExecStart=/app/phpservice/runner.sh phpfile parameter > /dev/null 2>/dev/null KillMode=process |
如果遇到内存泄漏,此方法也有效。
Note: Every time that you change your"myphpdaemon.service" you must
run `systemctl daemon-reload', but do worry if you not do, it will be
prompted when is needed.
我运行了大量的PHP守护进程。
我同意你的观点,PHP并不是最好的(甚至是一种好的)语言,但是守护进程与面向Web的组件共享代码,所以总的来说,它是一个很好的解决方案。
我们为此使用daemontools。它智能、干净、可靠。实际上,我们使用它来运行所有守护进程。
您可以在http://cr.yp.to/daemontools.html上查看。
编辑:功能的快速列表。
- 重新启动时自动启动守护程序
- 失败时自动重新启动Dameon
- 日志记录是为您处理的,包括滚动和修剪
- 管理接口:"svc"和"svstat"
- Unix友好型(可能不是每个人的优势)
你可以
我建议使用最简单的方法(在我看来是屏幕),如果您想要更多的功能或功能,请转到更复杂的方法。
有多种方法可以解决这个问题。
我不知道具体细节,但也许还有另一种触发PHP进程的方法。例如,如果需要根据SQL数据库中的事件运行代码,可以设置触发器来执行脚本。这在PostgreSQL下很容易做到:http://www.postgresql.org/docs/current/static/external-pl.html。
老实说,我认为你最好的选择是用nohup创建一个damon进程。nohup允许命令继续执行,即使用户已注销:
1 | nohup php myscript.php & |
但是有一个非常严重的问题。正如您所说,PHP的内存管理器是完全垃圾,它是在假设脚本只执行几秒钟然后就存在的情况下构建的。您的PHP脚本将在几天后开始使用千兆字节的内存。您还必须创建一个cron脚本,该脚本每隔12或24小时运行一次,以杀死并重新生成您的PHP脚本,如下所示:
1 2 | killall -3 php nohup php myscript.php & |
但如果剧本在工作中呢?well kill-3是一个中断,与在cli上执行ctrl+c相同。您的PHP脚本可以捕获这个中断并使用php pcntl库优雅地退出:http://php.oregonstate.edu/manual/en/function.pcntl-signal.php
下面是一个例子:
1 2 3 4 5 6 7 | function clean_up() { GLOBAL $lock; mysql_close(); fclose($lock) exit(); } pcntl_signal(SIGINT, 'clean_up'); |
$lock背后的思想是PHP脚本可以用fopen("file","w")打开一个文件。一个文件只能有一个进程有一个写锁,因此使用它可以确保只有一个PHP脚本副本在运行。
祝你好运!
Kevin van Zonneveld写了一篇非常详细的文章,在他的例子中,他使用了
查看https://github.com/shaneharter/php-daemon
这是一个面向对象的守护程序库。它内置了日志记录和错误恢复等功能,并支持创建后台工作人员。
我最近需要一个跨平台的解决方案(Windows、Mac和Linux)来解决将PHP脚本作为守护进程运行的问题。我通过编写自己的基于C++的解决方案和二进制文件来解决这个问题:
https://github.com/cubiclesoft/service-manager/
完全支持Linux(通过Sysvinit),也支持Windows NT服务和Mac OSX启动。
如果您只需要Linux,那么这里提供的其他两个解决方案就可以很好地工作,这取决于其风格。现在也有一些新贵和SystemD,它们有对Sysvinit脚本的回退。但是使用PHP的一半意义在于它本质上是跨平台的,因此用该语言编写的代码有很好的机会在任何地方工作。当某些外部本机操作系统级别的方面(如系统服务)进入图片时,缺陷就会出现,但大多数脚本语言都会遇到这个问题。
尝试像这里php userland中建议的那样捕捉信号不是一个好主意。仔细阅读
随着时间的推移,PHP在内存泄漏问题上的表现也越来越好。您仍然需要小心(domxml解析器仍然容易泄漏),但是最近我很少看到失控的进程,而且与以前相比,php bug跟踪器相当安静。
扩展emil ivav答案,可以执行以下操作关闭php中的stdin、stdout和stderror
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
基本上,关闭标准流,这样PHP就没有地方可写了。下面的
我从网上的rob aley-php书中读到了这个。
正如其他人已经提到的,将PHP作为守护进程运行非常容易,并且可以使用一行命令来完成。但真正的问题是保持它的运行和管理。很久以前我也遇到过同样的问题,虽然已经有很多解决方案可用,但大多数都有很多依赖项,或者很难使用,不适合基本用途。我编写了一个shell脚本,可以管理任何进程/应用程序,包括php cli脚本。它可以设置为cronjob来启动应用程序,并包含应用程序并对其进行管理。如果它被再次执行,例如通过同一个cronjob,它会检查应用程序是否正在运行,如果它正在运行,那么只需退出,让它的前一个实例继续管理应用程序。
我把它上传到了Github,请随意使用:https://github.com/sinasalek/easydeamonizer
易去污剂
只需监视应用程序(启动、重新启动、日志、监视器等)。一个通用脚本,用于确保应用程序正常运行。故意使用pid/lock文件的进程名instread来防止其所有副作用,并尽可能保持脚本的简单性和前向性,因此即使easydaemonizer本身重新启动,它也始终有效。特征
- 启动应用程序,并且可以选择每次启动的自定义延迟
- 确保只有一个实例正在运行
- 监控CPU使用情况,当应用程序达到定义的阈值时自动重新启动应用程序
- 将easydeamonizer设置为通过cron运行,以便在因任何原因停止时再次运行它。
- 记录其活动
您可以在这里查看pm2,http://pm2.keymetrics.io/
创建一个ssh文件,比如worker.sh,放入您将要处理的PHP脚本中。
工匠
1 | php /path/myscript.php |
守护进程启动
1 | pm2 start worker.sh |
干杯,就这样。
我编写并部署了一个简单的php守护进程,代码在这里联机
https://github.com/jmullee/phpunixdaemon
特点:权限丢弃、信号处理、日志记录
我在队列处理程序中使用了它(用例:从网页触发一个冗长的操作,而不让生成PHP的页面等待,即启动一个异步操作)。https://github.com/jmullee/phpipcmessagequeue