Linux 将 php 脚本作为守护进程运行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2036654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:40:19  来源:igfitidea点击:

Run php script as daemon process

phplinuxunixdaemon

提问by Beier

I need to run a php script as daemon process (wait for instructions and do stuff). cron job will not do it for me because actions need to be taken as soon as instruction arrives. I know PHP is not really the best option for daemon processes due to memory management issues, but due to various reasons I have to use PHP in this case. I came across a tool by libslack called Daemon (http://libslack.org/daemon) it seems to help me manage daemon processes, but there hasn't been any updates in the last 5 years, so I wonder if you know some other alternatives suitable for my case. Any information will be really appreciated.

我需要运行一个 php 脚本作为守护进程(等待指令并做一些事情)。cron 作业不会为我做这件事,因为一旦指令到达就需要采取行动。我知道由于内存管理问题,PHP 并不是守护进程的最佳选择,但由于各种原因,我必须在这种情况下使用 PHP。我遇到了 libslack 的一个名为 Daemon ( http://libslack.org/daemon)的工具,它似乎可以帮助我管理守护进程,但是最近 5 年没有任何更新,所以我想知道您是否知道一些其他适合我的情况的替代方案。任何信息将不胜感激。

采纳答案by Henrik P. Hessel

You could start your php script from the command line (i.e. bash) by using

您可以使用以下命令从命令行(即 bash)启动您的 php 脚本

nohup php myscript.php &

nohup php myscript.php &

the &puts your process in the background.

&把你的程序在后台运行。

Edit:
Yes, there are some drawbacks, but not possible to control? That's just wrong.
A simple kill processidwill stop it. And it's still the best and simplest solution.

编辑:
是的,有一些缺点,但无法控制?那是错误的。
一个简单的kill processid将阻止它。它仍然是最好和最简单的解决方案。

回答by Emil Ivanov

If you can - grab a copy of Advanced Programming in the UNIX Environment. The entire chapter 13 is devoted to daemon programming. Examples are in C, but all the function you need have wrappers in PHP (basically the pcntland posixextensions).

如果可以,请获取UNIX 环境中高级编程的副本。整个第 13 章专门讨论守护程序编程。示例是用 C 语言编写的,但您需要的所有函数都在 PHP 中有包装器(基本上是pcntlposix扩展)。

In a few words - writing a daemon (this is posible only on *nix based OS-es - Windows uses services) is like this:

简而言之 - 编写守护进程(这仅在基于 *nix 的 OS-es 上可行 - Windows 使用服务)是这样的:

  1. Call umask(0)to prevent permission issues.
  2. fork()and have the parent exit.
  3. Call setsid().
  4. Setup signal processing of SIGHUP(usually this is ignored or used to signal the daemon to reload its configuration) and SIGTERM(to tell the process to exit gracefully).
  5. fork()again and have the parent exit.
  6. Change the current working dir with chdir().
  7. fclose()stdin, stdoutand stderrand don't write to them. The corrrect way is to redirect those to either /dev/nullor a file, but I couldn't find a way to do it in PHP. It is possible when you launch the daemon to redirect them using the shell (you'll have to find out yourself how to do that, I don't know :).
  8. Do your work!
  1. 调用umask(0)以防止权限问题。
  2. fork()并让父母退出。
  3. 打电话setsid()
  4. 设置信号处理SIGHUP(通常会被忽略或用于通知守护进程重新加载其配置)和SIGTERM(告诉进程正常退出)。
  5. fork()再次让父退出。
  6. 更改当前工作目录chdir()
  7. fclose()stdinstdout并且stderr不要写信给他们。正确的方法是将它们重定向到任/dev/null一文件或文件,但我找不到在 PHP 中执行此操作的方法。当您启动守护程序时,可以使用 shell 重定向它们(您必须自己找出如何做到这一点,我不知道 :)。
  8. 做你的工作!

Also, since you are using PHP, be careful for cyclic references, since the PHP garbage collector, prior to PHP 5.3, has no way of collecting those references and the process will memory leak, until it eventually crashes.

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

回答by Alix Axel

Kevin van Zonneveld wrote a very nice detailed article on this, in his example he makes use of the System_DaemonPEAR package(last release date on 2009-09-02).

Kevin van Zonneveld在这方面写了一篇非常详细的文章,在他的示例中,他使用了System_DaemonPEAR 包(最后发布日期为 2009-09-02)。

回答by rook

There is more than one way to solve this problem.

解决这个问题的方法不止一种。

I do not know the specifics but perhaps there is another way to trigger the PHP process. For instance if you need the code to run based on events in a SQL database you could setup a trigger to execute your script. This is really easy to do under PostgreSQL: http://www.postgresql.org/docs/current/static/external-pl.html.

我不知道具体细节,但也许有另一种方式来触发 PHP 进程。例如,如果您需要基于 SQL 数据库中的事件运行代码,您可以设置触发器来执行您的脚本。这在 PostgreSQL 下很容易做到:http: //www.postgresql.org/docs/current/static/external-pl.html

Honestly I think your best bet is to create a Damon process using nohup. nohup allows the command to continue to execute even after the user has logged out:

老实说,我认为最好的办法是使用 nohup 创建一个 Damon 进程。nohup 允许命令在用户注销后继续执行:

nohup php myscript.php &

There is however a very serious problem. As you said PHP's memory manager is complete garbage, it was built with the assumption that a script is only executing for a few seconds and then exists. Your PHP script will start to use GIGABYTES of memory after only a few days. You MUST ALSO create a cron script that runs every 12 or maybe 24 hours that kills and re-spawns your php script like this:

然而,有一个非常严重的问题。正如您所说,PHP 的内存管理器完全是垃圾,它是在假设脚本仅执行几秒钟然后存在的假设下构建的。您的 PHP 脚本将在几天后开始使用 GIGABYTES 的内存。您还必须创建一个 cron 脚本,它每 12 小时或 24 小时运行一次,它会像这样杀死并重新生成您的 php 脚本:

killall -3 php
nohup php myscript.php &

But what if the script was in the middle of a job? Well kill -3 is an interrupt, its the same as doing a ctrl+c on the CLI. Your php script can catch this interrupt and exit gracefully using the PHP pcntl library: http://php.oregonstate.edu/manual/en/function.pcntl-signal.php

但是如果脚本在工作中呢?好吧,kill -3 是一个中断,它与在 CLI 上执行 ctrl+c 相同。您的 php 脚本可以使用 PHP pcntl 库捕获此中断并正常退出:http://php.oregonstate.edu/manual/en/function.pcntl-signal.php

Here is an example:

下面是一个例子:

function clean_up() {
  GLOBAL $lock;
  mysql_close();
  fclose($lock)
  exit();
}
pcntl_signal(SIGINT, 'clean_up');

The idea behind the $lock is that the PHP script can open a file with a fopen("file","w");. Only one process can have a write lock on a file, so using this you can make sure that only one copy of your PHP script is running.

$lock 背后的想法是 PHP 脚本可以使用 fopen("file","w"); 打开文件。只有一个进程可以对文件拥有写锁,因此使用它可以确保只有一个 PHP 脚本副本正在运行。

Good Luck!

祝你好运!

回答by Phil Wallach

I run a large number of PHP daemons.

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

I agree with you that PHP is not the best (or even a good) language for doing this, but the daemons share code with the web-facing components so overall it is a good solution for us.

我同意您的看法,PHP 不是执行此操作的最佳(甚至不是好)语言,但守护进程与面向 Web 的组件共享代码,因此总体而言,它对我们来说是一个很好的解决方案。

We use daemontools for this. It is smart, clean and reliable. In fact we use it for running all of our daemons.

为此,我们使用 daemontools。它智能、干净且可靠。事实上,我们使用它来运行我们所有的守护进程。

You can check this out at http://cr.yp.to/daemontools.html.

您可以在http://cr.yp.to/daemontools.html 上查看。

EDIT: A quick list of features.

编辑:功能的快速列表。

  • Automatically starts the daemon on reboot
  • Automatically restart dameon on failure
  • Logging is handled for you, including rollover and pruning
  • Management interface: 'svc' and 'svstat'
  • UNIX friendly (not a plus for everyone perhaps)
  • 重新启动时自动启动守护程序
  • 失败时自动重启 dameon
  • 为您处理日志记录,包括翻转和修剪
  • 管理接口:'svc' 和 'svstat'
  • UNIX 友好(可能不是每个人的加分项)

回答by Noufal Ibrahim

You can

你可以

  1. Use nohupas Henrik suggested.
  2. Use screenand run your PHP program as a regular process inside that. This gives you more control than using nohup.
  3. Use a daemoniser like http://supervisord.org/(it's written in Python but can daemonise any command line program and give you a remote control to manage it).
  4. Write your own daemonise wrapper like Emil suggested but it's overkill IMO.
  1. nohup按照 Henrik 的建议使用。
  2. 使用screen和运行您的 PHP 程序作为其中的常规进程。这比使用nohup.
  3. 使用像http://supervisord.org/这样的守护程序(它是用 Python 编写的,但可以守护任何命令行程序并为您提供远程控制来管理它)。
  4. 像 Emil 建议的那样编写自己的守护程序包装器,但 IMO 太过分了。

I'd recommend the simplest method (screen in my opinion) and then if you want more features or functionality, move to more complex methods.

我会推荐最简单的方法(我认为是屏幕),然后如果您想要更多特性或功能,请转向更复杂的方法。

回答by Shane H

Check out https://github.com/shaneharter/PHP-Daemon

查看https://github.com/shaneharter/PHP-Daemon

This is an object-oriented daemon library. It has built-in support for things like logging and error recovery, and it has support for creating background workers.

这是一个面向对象的守护进程库。它内置了对日志记录和错误恢复等内容的支持,并支持创建后台工作程序。

回答by Jonathan

Another option is to use Upstart. It was originally developed for Ubuntu (and comes packaged with it by default), but is intended to be suitable for all Linux distros.

另一种选择是使用Upstart。它最初是为 Ubuntu 开发的(默认情况下与它打包在一起),但旨在适用于所有 Linux 发行版。

This approach is similar to Supervisordand daemontools, in that it automatically starts the daemon on system boot and respawns on script completion.

这种方法类似于Supervisorddaemontools,因为它在系统启动时自动启动守护程序并在脚本完成时重新生成。

How to set it up:

如何设置:

Create a new script file at /etc/init/myphpworker.conf. Here is an example:

/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

Starting & stopping your daemon:

启动和停止你的守护进程:

sudo service myphpworker start
sudo service myphpworker stop

Check if your daemon is running:

检查您的守护进程是否正在运行:

sudo service myphpworker status

Thanks

谢谢

A big thanks to Kevin van Zonneveld, where I learned this technique from.

非常感谢Kevin van Zonneveld,我从那里学到了这项技术。

回答by Sina Salek

As others have already mentioned, running PHP as a daemon is quite easy, and can be done using a single line of command. But the actual problem is keeping it running and managing it. I've had the same problem quite some time ago and although there are plenty of solutions already available, most of them have lots of dependencies or are difficult to use and not suitable for basic usages. I wrote a shell script that can manage a any process/application including PHP cli scripts. It can be set as a cronjob to start the application and will contain the application and manage it. If it's executed again, for example via the same cronjob, it check if the app is running or not, if it does then simply exits and let its previous instance continue managing the application.

正如其他人已经提到的,将 PHP 作为守护程序运行非常容易,并且可以使用单行命令完成。但实际的问题是保持它运行和管理它。很久以前我也遇到过同样的问题,尽管已经有很多解决方案可用,但其中大多数都有很多依赖项或难以使用且不适合基本用途。我编写了一个 shell 脚本,可以管理任何进程/应用程序,包括 PHP cli 脚本。它可以设置为启动应用程序的cronjob,并将包含应用程序并对其进行管理。如果它再次执行,例如通过相同的 cronjob,它会检查应用程序是否正在运行,如果运行,则直接退出并让其前一个实例继续管理应用程序。

I uploaded it to github, feel free to use it : https://github.com/sinasalek/EasyDeamonizer

我已上传到github,请随意使用:https: //github.com/sinasalek/EasyDeamonizer

EasyDeamonizer

EasyDeamonizer

Simply watches over your application (start, restart, log, monitor, etc). a generic script to make sure that your appliation remains running properly. Intentionally it uses process name instread of pid/lock file to prevent all its side effects and keep the script as simple and as stirghforward as possible, so it always works even when EasyDaemonizer itself is restarted. Features

只需监视您的应用程序(启动、重启、记录、监控等)。一个通用脚本,以确保您的应用程序保持正常运行。它故意使用进程名称 instread pid/lock 文件来防止其所有副作用,并使脚本尽可能简单和快速,因此即使在 EasyDaemonizer 本身重新启动时它也始终有效。特征

  • Starts the application and optionally a customized delay for each start
  • Makes sure that only one instance is running
  • Monitors CPU usage and restarts the app automatically when it reaches the defined threshold
  • Setting EasyDeamonizer to run via cron to run it again if it's halted for any reason
  • Logs its activity
  • 启动应用程序和可选的每次启动的自定义延迟
  • 确保只有一个实例正在运行
  • 监控 CPU 使用率并在达到定义的阈值时自动重启应用程序
  • 将 EasyDeamonizer 设置为通过 cron 运行以在它因任何原因停止时再次运行
  • 记录其活动

回答by CubicleSoft

I recently had a need for a cross-platform solution (Windows, Mac, and Linux) to the problem of running PHP scripts as daemons. I solved the problem by writing my own C++ based solution and making binaries:

我最近需要一个跨平台的解决方案(Windows、Mac 和 Linux)来解决将 PHP 脚本作为守护程序运行的问题。我通过编写自己的基于 C++ 的解决方案并制作二进制文件解决了这个问题:

https://github.com/cubiclesoft/service-manager/

https://github.com/cubiclesoft/service-manager/

Full support for Linux (via sysvinit), but also Windows NT services and Mac OSX launchd.

完全支持 Linux(通过 sysvinit),但也支持 Windows NT 服务和 Mac OSX launchd。

If you just need Linux, then a couple of the other solutions presented here work well enough and, depending on the flavor. There is also Upstart and systemd these days, which have fallbacks to sysvinit scripts. But half of the point of using PHP is that it is cross-platform in nature, so code written in the language has a pretty good chance of working everywhere as-is. Deficiencies start showing up when certain external native OS-level aspects enter the picture such as system services, but you'll get that problem with most scripting languages.

如果您只需要 Linux,那么这里介绍的其他几个解决方案工作得很好,具体取决于风格。这些天还有 Upstart 和 systemd,它们可以回退到 sysvinit 脚本。但是使用 PHP 的一半原因在于它本质上是跨平台的,所以用这种语言编写的代码很有可能在任何地方都可以正常工作。当某些外部本机操作系统级别方面(例如系统服务)进入画面时,缺陷就会开始出现,但是大多数脚本语言都会遇到这个问题。

Attempting to catch signals as someone here suggested in PHP userland is not a good idea. Read the documentation on pcntl_signal()carefully and you will quickly learn that PHP handles signals using some rather unpleasant methods (specifically, 'ticks') that chew up a bunch of cycles for something rarely seen by processes (i.e. signals). Signal handling in PHP is also only barely available on POSIX platforms and support differs based on the version of PHP. It initially sounds like a decent solution but it falls pretty short of being truly useful.

尝试像这里有人在 PHP userland 中建议的那样捕获信号不是一个好主意。pcntl_signal()仔细阅读文档,您将很快了解到 PHP 使用一些相当不愉快的方法(特别是“滴答”)处理信号,这些方法会为进程很少看到的东西(即信号)咀嚼一堆循环。PHP 中的信号处理也仅在 POSIX 平台上几乎不可用,并且支持因 PHP 版本而异。它最初听起来是一个不错的解决方案,但它并没有真正有用。

PHP has also been getting better about memory leak issues as time progresses. You still have to be careful (the DOM XML parser tends to leak still) but I rarely see runaway processes these days and the PHP bug tracker is pretty quiet by comparison to the days of yore.

随着时间的推移,PHP 在内存泄漏问题上也变得越来越好。您仍然必须小心(DOM XML 解析器仍然倾向于泄漏)但是我现在很少看到失控的进程,与过去相比,PHP 错误跟踪器非常安静。