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

发布于 2024-08-17 12:30:41 字数 306 浏览 6 评论 0原文

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

相对绾红妆 2024-08-24 12:30:41

来从命令行(即 bash)启动 php 脚本,

您可以使用nohup php myscript.php &

& 将您的进程置于后台。

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

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

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 processid will stop it. And it's still the best and simplest solution.

涫野音 2024-08-24 12:30:41

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

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

如何设置:

/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,我从那里学到了这项技术。

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.

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

How to set it up:

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

# 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.

贱人配狗天长地久 2024-08-24 12:30:41

使用新的 systemd 您可以创建一个服务。

您必须在 /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

您将能够使用命令

systemctlmyphpdaemon

您可以通过 php -S 127.0.0.1: 使用 PHP 本机服务器或将其作为脚本运行。使用 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
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 例程应在一个周期内执行一次(如摘要),您可以使用 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(main) 和 PHP(child) 被杀死。

ExecStart=/app/phpservice/runner.sh phpfile parameter  > /dev/null 2>/dev/null
KillMode=process

如果您面临内存泄漏,此方法也很有效。

注意:每次更改“myphpdaemon.service”时,您都必须
运行“systemctl daemon-reload”,但请担心如果不这样做,它会
需要时发出警报。

With new systemd you can create a service.

You must create a file or a symlink in /etc/systemd/system/, eg. myphpdaemon.service and place content like this one, myphpdaemon will be the name of the service:

[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

You will be able to start, get status, restart and stop the services using the command

systemctl <start|status|restart|stop|enable> myphpdaemon

You can use the PHP native server using php -S 127.0.0.1:<port> or run it as a script. Using a PHP script you should have a kind of "forever loop" to continue running.

<?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
        }
    }
}

Working example:

[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

If your PHP routine should be executed once in a cycle (like a diggest) you may use a shell or bash script to be invoked into systemd service file instead of PHP directly, for example:

#!/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

If you chose these option you should change the KillMode to mixed to processes, bash(main) and PHP(child) be killed.

ExecStart=/app/phpservice/runner.sh phpfile parameter  > /dev/null 2>/dev/null
KillMode=process

This method also is effective if you're facing a memory leak.

Note: Every time that you change your "myphpdaemon.service" you must
run `systemctl daemon-reload', but do worry if you do not do, it will be
alerted when is needed.

草莓味的萝莉 2024-08-24 12:30:41

如果可以的话 - 获取UNIX 环境中的高级编程的副本。整个第 13 章都致力于守护进程编程。示例是用 C 编写的,但是您需要的所有函数都有 PHP 中的包装器(基本上是 pcntlposix 扩展)。

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

  1. Call umask(0) 以防止权限问题。
  2. fork() 并拥有父出口。
  3. 调用 setsid()
  4. 设置 SIGHUP 的信号处理(通常会被忽略或用于向守护进程发出信号以重新加载其配置)和 SIGTERM (告诉进程正常退出)。
  5. 再次fork()并让父进程退出。
  6. 使用 chdir() 更改当前工作目录。
  7. fclose() stdin, stdout 和 stderr 并且不要写入它们。正确的方法是将它们重定向到 /dev/null 或文件,但我找不到在 PHP 中执行此操作的方法。当您启动守护进程时,可以使用 shell 重定向它们(您必须自己找出如何做到这一点,我不知道:)。
  8. 做好你的工作吧!

另外,由于您使用的是 PHP,所以要小心循环引用,因为 PHP 5.3 之前的 PHP 垃圾收集器无法收集这些引用,并且该进程将发生内存泄漏,直到最终崩溃。

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 pcntl and posix extensions).

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

  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, stdout and stderr and don't write to them. The corrrect way is to redirect those to either /dev/null or 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!

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.

小情绪 2024-08-24 12:30:41

我运行大量 PHP 守护进程。

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

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

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

编辑:功能的快速列表。

  • 重新启动时自动启动守护
  • 进程 出现故障时自动重新启动守护进程
  • 为您处理日志记录,包括翻转和修剪
  • 管理界面:'svc' 和 'svstat'
  • UNIX 友好(也许不是每个人都有优点)

I run a large number of PHP daemons.

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.

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

You can check this out at 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)
梦里的微风 2024-08-24 12:30:41

您可以

  1. 按照 Henrik 的建议使用 nohup
  2. 使用 screen 并将 PHP 程序作为其中的常规进程运行。与使用 nohup 相比,这为您提供了更多的控制权。
  3. 使用像 http://supervisord.org/ 这样的守护进程(它是用 Python 编写的,但可以守护任何命令行程序并提供您可以使用遥控器来管理它)。
  4. 像 Emil 建议的那样编写自己的守护进程包装器,但在我看来这有点过分了。

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

You can

  1. Use nohup as Henrik suggested.
  2. Use screen and 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.

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

妄想挽回 2024-08-24 12:30:41

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

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

但是,如果该脚本正在执行作业怎么办?那么kill -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 脚本正在运行。

祝你好运!

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 .

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 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:

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

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.

Good Luck!

岁吢 2024-08-24 12:30:41

Kevin van Zonneveld 就此写了一篇非常详细的文章,在他的示例中,他使用了System_Daemon PEAR 包(最后发布日期为 2009 年 9 月 - 02)。

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

提笔书几行 2024-08-24 12:30:41

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

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

Check out 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.

梦断已成空 2024-08-24 12:30:41

我最近需要一个跨平台解决方案(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 使用一些相当令人不快的方法(特别是“ticks”)来处理信号,这些方法会消耗掉一堆进程很少看到的循环(即信号)。 PHP 中的信号处理也仅在 POSIX 平台上几乎可用,并且支持因 PHP 版本而异。它最初听起来像是一个不错的解决方案,但它距离真正有用还差得很远。

随着时间的推移,PHP 在内存泄漏问题上也得到了更好的解决。您仍然必须小心(DOM XML 解析器仍然会泄漏),但现在我很少看到失控的进程,而且与以前相比,PHP 错误跟踪器非常安静。

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:

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

Full support for Linux (via sysvinit), but also Windows NT services and 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.

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 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.

滥情空心 2024-08-24 12:30:41

你可以在这里检查pm2,http://pm2.keymetrics.io/

创建一个ssh文件,比如将worker.sh放入您将要处理的php脚本中。

worker.sh

php /path/myscript.php

守护进程启动

pm2 start worker.sh

干杯,就是这样。

you can check pm2 here is, http://pm2.keymetrics.io/

create a ssh file, such as worker.sh put into your php script that you will deal with.

worker.sh

php /path/myscript.php

daemon start

pm2 start worker.sh

Cheers, that is it.

一个人的旅程 2024-08-24 12:30:41

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

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

EasyDeamonizer

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

  • 启动应用程序,并可选择为每次启动设置自定义延迟
  • 确保只有一个实例正在运行
  • 监控 CPU 使用情况,并在达到定义的阈值时自动重新启动应用程序
  • 将 EasyDeamonizer 设置为通过 cron 运行,以便在因任何原因停止时再次运行它
  • 记录其活动

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.

I uploaded it to github, feel free to use it : https://github.com/sinasalek/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

  • 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
灰色世界里的红玫瑰 2024-08-24 12:30:41

我一直在寻找一个简单的解决方案,无需安装额外的东西,并且与允许 SSH 访问的常见主机兼容。

我最终为我的聊天服务器设置了这样的设置:

-rwxr-xr-x  1 crazypoems psacln   309 ene 30 14:01 checkChatServerRunning.sh
-rw-r--r--  1 crazypoems psacln  3018 ene 30 13:12 class.chathandler.php
-rw-r--r--  1 crazypoems psacln    29 ene 30 14:05 cron.log
-rw-r--r--  1 crazypoems psacln  2560 ene 29 08:04 index.php
-rw-r--r--  1 crazypoems psacln  2672 ene 30 13:29 php-socket.php
-rwxr-xr-x  1 crazypoems psacln   310 ene 30 14:04 restartChatServer.sh
-rwxr-xr-x  1 crazypoems psacln   122 ene 30 13:28 startChatServer.sh
-rwxr-xr-x  1 crazypoems psacln   224 ene 30 13:56 stopChatServer.sh

脚本:

startChatServer.sh

#!/bin/bash
nohup /opt/plesk/php/5.6/bin/php -q /var/www/vhosts/crazypoems.org/httpdocs/chat/php-socket.php > /dev/null &

stopChatServer.sh

#!/bin/bash
PID=`ps -eaf | grep '/var/www/vhosts/crazypoems.org/httpdocs/chat/php-socket.php' | grep -v grep | awk '{print $2}'`
if [[ "" !=  "$PID" ]]; then
  echo "killing $PID"
  kill -9 $PID
else
  echo "not running"
fi

restartChatServer.sh

#!/bin/bash
PID=`ps -eaf | grep '/var/www/vhosts/crazypoems.org/httpdocs/chat/php-socket.php' | grep -v grep | awk '{print $2}'`
if [[ "" !=  "$PID" ]]; then
  echo "killing $PID"
  kill -9 $PID
else
  echo "not running"
fi
echo "Starting again"
/var/www/vhosts/crazypoems.org/httpdocs/chat/startChatServer.sh

最后但并非最不重要的一点是,我已将最后一个脚本放在 cron 作业上,以检查“聊天服务器”是否已启动正在运行”,如果没有,则启动它:

Cron job 每分钟

-bash-4.1$ crontab -l
*       *       *       *       * /var/www/vhosts/crazypoems.org/httpdocs/chat/checkChatServerRunning.sh > /var/www/vhosts/crazypoems.org/httpdocs/chat/cron.log

checkChatServerRunning.sh

#!/bin/bash
PID=`ps -eaf | grep '/var/www/vhosts/crazypoems.org/httpdocs/chat/php-socket.php' | grep -v grep | awk '{print $2}'`
if [[ "" !=  "$PID" ]]; then
  echo "Chat server running on $PID"
else
  echo "Not running, going to start it"
  /var/www/vhosts/crazypoems.org/httpdocs/chat/startChatServer.sh
fi

因此,通过此设置:

  • 我可以在需要时使用脚本手动控制服务(例如:维护)
  • cron 作业将在重新启动时启动服务器,或崩溃时

I was looking for a simple solution without having to install additional stuff and compatible with common hostings that allow SSH access.

I've ended up with this setup for my chat server:

-rwxr-xr-x  1 crazypoems psacln   309 ene 30 14:01 checkChatServerRunning.sh
-rw-r--r--  1 crazypoems psacln  3018 ene 30 13:12 class.chathandler.php
-rw-r--r--  1 crazypoems psacln    29 ene 30 14:05 cron.log
-rw-r--r--  1 crazypoems psacln  2560 ene 29 08:04 index.php
-rw-r--r--  1 crazypoems psacln  2672 ene 30 13:29 php-socket.php
-rwxr-xr-x  1 crazypoems psacln   310 ene 30 14:04 restartChatServer.sh
-rwxr-xr-x  1 crazypoems psacln   122 ene 30 13:28 startChatServer.sh
-rwxr-xr-x  1 crazypoems psacln   224 ene 30 13:56 stopChatServer.sh

And the scripts:

startChatServer.sh

#!/bin/bash
nohup /opt/plesk/php/5.6/bin/php -q /var/www/vhosts/crazypoems.org/httpdocs/chat/php-socket.php > /dev/null &

stopChatServer.sh

#!/bin/bash
PID=`ps -eaf | grep '/var/www/vhosts/crazypoems.org/httpdocs/chat/php-socket.php' | grep -v grep | awk '{print $2}'`
if [[ "" !=  "$PID" ]]; then
  echo "killing $PID"
  kill -9 $PID
else
  echo "not running"
fi

restartChatServer.sh

#!/bin/bash
PID=`ps -eaf | grep '/var/www/vhosts/crazypoems.org/httpdocs/chat/php-socket.php' | grep -v grep | awk '{print $2}'`
if [[ "" !=  "$PID" ]]; then
  echo "killing $PID"
  kill -9 $PID
else
  echo "not running"
fi
echo "Starting again"
/var/www/vhosts/crazypoems.org/httpdocs/chat/startChatServer.sh

And last but not least, I have put this last script on a cron job, to check if the "chat server is running", and if not, to start it:

Cron job every minute

-bash-4.1$ crontab -l
*       *       *       *       * /var/www/vhosts/crazypoems.org/httpdocs/chat/checkChatServerRunning.sh > /var/www/vhosts/crazypoems.org/httpdocs/chat/cron.log

checkChatServerRunning.sh

#!/bin/bash
PID=`ps -eaf | grep '/var/www/vhosts/crazypoems.org/httpdocs/chat/php-socket.php' | grep -v grep | awk '{print $2}'`
if [[ "" !=  "$PID" ]]; then
  echo "Chat server running on $PID"
else
  echo "Not running, going to start it"
  /var/www/vhosts/crazypoems.org/httpdocs/chat/startChatServer.sh
fi

So with this setup:

  • I manually can control the service with the scripts when needed (eg: maintenance)
  • The cron job will start the server on reboot, or on crash
早乙女 2024-08-24 12:30:41

我编写并部署了一个简单的 php-daemon,代码在线

https://github.com/jmullee/PhpUnixDaemon< /a>

功能:权限删除、信号处理、日志记录

我在队列处理程序中使用了它(用例:从网页触发冗长的操作,而不使页面生成的 php 等待,即启动异步操作)
https://github.com/jmullee/PhpIPCMessageQueue

I wrote and deployed a simple php-daemon, code is online here

https://github.com/jmullee/PhpUnixDaemon

Features: privilege dropping, signal handling, logging

I used it in a queue-handler (use case: trigger a lengthy operation from a web page, without making the page-generating php wait, i.e. launch an asynchronous operation)
https://github.com/jmullee/PhpIPCMessageQueue

小清晰的声音 2024-08-24 12:30:41

扩展 Emil Ivaov 答案,您可以执行以下操作来关闭 php 中的 STDIN、STDOUT 和 STDERROR

if (!fclose(STDIN)) {
    exit("Could not close STDIN");
}

if (!fclose(STDOUT)) {
    exit("Could not close STDOUT");
}

if (!fclose(STDERR)) {
    exit("Could not close STDERR");
}

$STDIN = fopen('/dev/null', 'r');
$STDOUT = fopen('/dev/null', 'w');
$STDERR = fopen('/var/log/our_error.log', 'wb');

基本上您关闭了标准流,以便 PHP 没有地方可写。以下 fopen 调用会将标准 IO 设置为 /dev/null

我从Rob Aley - PHP Beyond the web一书中读到了这篇文章

Extending Emil Ivaov answer, You can do the following to close STDIN, STDOUT AND STDERROR in php

if (!fclose(STDIN)) {
    exit("Could not close STDIN");
}

if (!fclose(STDOUT)) {
    exit("Could not close STDOUT");
}

if (!fclose(STDERR)) {
    exit("Could not close STDERR");
}

$STDIN = fopen('/dev/null', 'r');
$STDOUT = fopen('/dev/null', 'w');
$STDERR = fopen('/var/log/our_error.log', 'wb');

Basically you close the standard streams so that PHP has no place to write. The following fopen calls will set the standard IO to /dev/null.

I have read this from book of Rob Aley - PHP beyond the web

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文