mariano / li3_gearman
Lithium集成Gearman
Requires
Requires (Dev)
- phpunit/phpunit: ~3.7.16
This package is not auto-updated.
Last update: 2024-09-11 12:20:08 UTC
README
li3_gearman提供了[最优秀的RAD PHP框架] lithium与一种名为Gearman的框架之间的集成,该框架可以将工作分配给机器。
许可证
li3_gearman在[BSD许可证] 下发布。
安装
建议您将li3_gearman作为GIT子模块安装,以保持最新的升级。为此,切换到包含您的lithium应用程序的核心目录,然后执行
$ git submodule add https://github.com/mariano/li3_gearman.git libraries/li3_gearman
一旦您已下载li3_gearman并将其放置在您的主libraries
文件夹中,或app/libraries
文件夹中,您需要通过在app/config/bootstrap/libraries.php
文件的末尾放置以下内容来启用它
Libraries::add('li3_gearman');
显然,您需要在某处运行Gearman服务器。
使用方法
li3_gearman有两个主要元素:守护进程(一个名为gearmand
的lithium控制台命令)和用于触发任务的实用类。
这两个工具都需要您定义一个配置,其中指定哪些Gearman服务器可用。您可以通过在启动过程中某处使用Gearman
类的config()
方法来完成此操作。例如,要定义一个使用位于与您的lithium应用程序相同服务器的Gearman服务器的default
配置,请将以下代码添加到app/config/bootstrap/connections.php
\li3_gearman\Gearman::config(array( 'default' => array( 'servers' => '127.0.0.1' ) ));
一旦您有一个有效的配置,您就可以启动守护进程并开始触发任务。
使用supervisor运行守护进程
运行li3_gearman守护进程的推荐方法是使用supervisor或类似工具。以下是一个运行8个工作进程(假设应用程序位于/var/www
)的supervisor配置示例
[program:worker]
user=ubuntu
command=/usr/bin/php -f /var/www/libraries/lithium/console/lithium.php -- --app=/var/www gearmand work --blocking --verbose
process_name=%(program_name)s #%(process_num)s
numprocs=8
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/worker-%(process_num)s.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=10
stderr_logfile=/var/log/supervisor/worker-%(process_num)s-error.log
stderr_logfile_maxbytes=50MB
stderr_logfile_backups=10
手动运行守护进程
守护进程是一个名为gearmand
的lithium控制台命令。不带参数运行它将显示类似于以下的消息
USAGE
li3 gearmand start [<config>]
li3 gearmand shutdown
li3 gearmand restart
DESCRIPTION
Gearman daemon implementation in Lithium.
OPTIONS
ping
Test that at least a worker is working
start
Start the daemon using the given configuration.
shutdown
Stop the daemon. Only applicable if started in daemon mode.
restart
Restart the daemon. Only applicable if started in daemon mode.
--environment=<string>
Override environment to work on. Defaults to: environment set in bootstrap
--atomic
If enabled, once a worker has performed its job, it will quit and a new
worker will be spawned (thus this setting means that `resuscitate` is
automatically enabled, and `limit` set to 0). Default: enabled
--blocking
Enable to interact with Gearman in blocking mode. Default: disabled
--daemon
Enable to start daemon in a new process. Default: disabled
--limit=<int>
How many workers (in total) are allowed to be spawned before finishing
daemon. Set to 0 to not limit spawned worker count. Default: 8
--pid=<string>
Location of PID file. Only applicable if daemon mode is enabled.
Default: /var/run/li3_gearman.pid
--resuscitate
If enabled, there will always be the number of workers defined in the
setting "workers". If a worker dies, another one will take its place,
up until the "limit" setting is reached. If disabled, no new
workers will be spawned after the initial set is started.
Default: disabled
--verbose
Enable to print out debug messages. If not enabled, messages go to
user's syslog (usually /var/log/user.log). Default: disabled
--workers=<int>
How many workers to run. Default: 4
守护进程可以以全守护进程模式运行(这意味着创建一个与控制台分离的新进程来处理工作进程),或者以交互式模式运行。默认情况下,它将以交互式模式运行,但您可以使用--daemon
选项切换到守护进程模式。
无论您决定使用哪种方法,请注意都会生成一定数量的工作进程(进程)。此数字受--workers
选项控制。如果您想确保始终有一定数量的活动工作进程处理任务,请使用--resuscitate
选项,该选项将定期遍历池以在其他工作进程完成时重新启动工作进程,无论出于什么原因。您还可以使用--limit
选项限制由复苏产生的总工作进程数。
测试
一旦启动了守护进程,您可以通过使用ping
命令快速测试设置是否正常工作。例如
$ li3 gearmand ping --verbose Pinging... OK
添加Initscript
如果您希望li3_gearman在启动时启动并在关闭时相应地关闭,您可能需要查看您本地系统的init脚本。如果您使用的是[Initscripts] linux-initscripts,那么这会变得相当简单。创建一个名为li3_gearmand
的文件,将其设置为可执行文件(chmod +x li3_gearmand
),并将其放置在您的initscripts目录中(通常是/etc/rc.d
或/etc/init.d
),内容如下
添加initscript并运行必要的命令,以便您的initscript可以自动启动,这绝对不是您应该做的唯一事情。您应该确保您有一种监控工具,以便在守护进程崩溃或没有活跃的工人在等待任务时可以重新启动守护进程。这个工具很棒的是monit monit,去看看吧。
#!/bin/bash # Uncomment and change the line below to match the app/ directory of your # lithium application #li3_app=/path/to/app . /etc/rc.conf . /etc/rc.d/functions if [ -z "$li3_app" ]; then echo "You must set \$li3_app to point to your lithium's app/ folder" stat_fail exit 1 fi if [ -z "$li3" ]; then li3_core=${li3_app%/*} if [ -x "li3" ]; then li3="li3" elif [ -x "$li3_app/app/libraries/lithium/console/li3" ]; then li3="$li3_app/app/libraries/lithium/console/li3" elif [ -x "$li3_core/libraries/lithium/console/li3" ]; then li3="$li3_core/libraries/lithium/console/li3" fi fi if [ -z "$li3" -o ! -x "$li3" ]; then echo $li3 echo "You must set \$li3 to point to the li3 console binary" stat_fail exit 1 fi daemon_bin="$li3 --app=$li3_app gearmand" daemon_name=$(basename $0) PIDF="/var/run/$daemon_name.pid" get_pid() { [ -f $PIDF ] && cat $PIDF } case "$1" in start) stat_busy "Starting $daemon_name daemon" PID=$(get_pid) if [ -z "$PID" ]; then [ -f $PIDF ] && rm -f $PIDF $daemon_bin start --blocking --daemon --pid=$PIDF if [ $? -gt 0 ]; then stat_fail exit 1 else add_daemon $daemon_name stat_done fi else stat_fail exit 1 fi ;; stop) stat_busy "Stopping $daemon_name daemon" PID=$(get_pid) # KILL [ ! -z "$PID" ] && kill $PID &> /dev/null # if [ $? -gt 0 ]; then stat_fail exit 1 else rm_daemon $daemon_name rm -f $PIDF &> /dev/null stat_done fi ;; restart) $0 stop sleep 3 $0 start ;; status) stat_busy "Checking $daemon_name status"; ck_status $daemon_name ;; *) echo "usage: $0 {start|stop|restart|status}" esac exit 0
确保将变量$li3_app
更改为与您的应用程序的app/
目录匹配。一旦完成,您就可以像通常那样使用initscripts启动/重启/关闭守护进程。例如,您可以使用以下命令启动守护进程:
$ rc.d start li3_gearmand
触发任务
可以使用Gearman::run()
方法触发任务。此方法接受以下参数
-
configName
:要使用的配置名称(参见上面的使用部分) -
action
:要执行的操作。如果使用li3_gearman附带默认的Job
适配器,则此应为一个完全限定的方法。这意味着它应包括一个完全限定的类名(带有命名空间)和一个方法名。如果没有提供方法名,则假定给定类的run()
方法。示例app\tasks\Email::send
app\tasks\Caching
-
args
:传递给操作参数。数组中的第一个元素将是第一个参数。第二个元素将是第二个参数,依此类推。 -
options
:影响适配器触发作业的选项。如果使用默认的Job
适配器,则可用的选项是background
:是否在后台触发任务。如果设置为false
,则任务将同步执行,并返回其结果。如果设置为true
,则返回作业句柄。有关作业句柄的更多信息,请参阅[关于Gearman的doBackground文档] gearman-doc-dobackground。默认为true
。priority
:要赋予作业的优先级。可以是low
、normal
或high
中的任何一个。默认为normal
。
触发作业时,可用的一个工作者(由li3_gearman的gearmand
守护进程启动)将在控制台中处理并执行它。这意味着lithium的调度周期中可用的任何资源都立即可用于作业。因此,您可以使用您的模型、插件等!
示例
在开始此示例之前,请确保您已按照安装部分中所述安装li3_gearman,并且您已添加默认配置,如使用部分开头所示。
让我们首先创建一个名为Hello
的任务。创建一个名为tasks
的文件夹,并将其放置在您的应用程序的app
文件夹中。在该文件夹中,创建一个名为Hello.php
的文件,内容如下
<?php namespace app\tasks; class Hello { public static function run() { echo "I am " . __METHOD__ . "\n"; } public static function say($name) { echo "I am " . __METHOD__ . "\n"; return 'Hello ' . $name; } } ?>
现在,让我们添加代码以触发一些任务,包括在后台和同步模式中。创建一个名为TestHelloController.php
的文件,并将其放置在您的app/controllers
文件夹中,内容如下
<?php namespace app\controllers; use \li3_gearman\Gearman; class TestHelloController extends \lithium\action\Controller { public function index() { $result = Gearman::run('default', 'app\tasks\Hello'); var_dump($result); $result = Gearman::run('default', 'app\tasks\Hello::say', array( 'Mariano' ), array('background' => false)); var_dump($result); $this->_stop(); } } ?>
好的,我们现在可以开始启动守护进程了。出于测试目的(在撰写本文时,PHP Gearman 扩展在非阻塞模式下运行时存在[一些问题] php-bug-60764),我将使用阻塞模式运行它。由于我们还想看到一些输出,我们将要求守护进程以详细模式运行。在您的 lithium 核心目录下运行
$ li3 gearmand start --verbose --blocking
您应该看到类似以下输出(控制台不会返回到提示符,因为我们没有以守护进程模式运行)
li3_gearman[6331]: Daemon started with PID 6331
li3_gearman[6331]: (Daemon) Created worker number 1 with PID 6332
li3_gearman[6332]: (Worker) Starting worker
li3_gearman[6332]: (Worker) Creating Gearman worker
li3_gearman[6332]: (Worker) Registering function li3_gearman\extensions\command\Gearmand::run
li3_gearman[6331]: (Daemon) Created worker number 2 with PID 6333
li3_gearman[6333]: (Worker) Starting worker
li3_gearman[6333]: (Worker) Creating Gearman worker
li3_gearman[6333]: (Worker) Registering function li3_gearman\extensions\command\Gearmand::run
li3_gearman[6331]: (Daemon) Created worker number 3 with PID 6334
li3_gearman[6334]: (Worker) Starting worker
li3_gearman[6334]: (Worker) Creating Gearman worker
li3_gearman[6334]: (Worker) Registering function li3_gearman\extensions\command\Gearmand::run
li3_gearman[6331]: (Daemon) Created worker number 4 with PID 6335
li3_gearman[6335]: (Worker) Starting worker
li3_gearman[6335]: (Worker) Creating Gearman worker
li3_gearman[6335]: (Worker) Registering function li3_gearman\extensions\command\Gearmand::run
现在打开浏览器,访问我们刚才创建的控制器。如果您的应用程序位于 localhost
,则浏览到 https:///test_hello
。您应该在浏览器中看到以下输出
string 'H:eternauta:27' (length=14)
string 'Hello Mariano' (length=13)
显示的第一个值对应于第一个在后台模式下运行的作业触发器。这意味着给定值实际上是作业句柄。第二个值对应于在同步模式下运行的作业,因此这实际上是作业本身返回的值!
如果您切换到控制台,您应该看到以下输出,这是由于我们刚才运行的控制器动作产生的
li3_gearman[6473]: (Worker) Handling job
li3_gearman[6471]: (Worker) Handling job
I am app\tasks\Hello::run
I am app\tasks\Hello::say
计划/延迟 Gearman 作业
Gearman 不提供开箱即用的作业延迟计划支持。您发送给 Gearman 的每个作业都视为可立即执行。普遍认为,延迟任务是特定于应用程序的逻辑,因此 li3_gearmand 提供了这些任务。
为此,使用 Redis 作为后端来保存计划中的作业。当您配置 Gearman
实例(参见上面的使用部分)时,请确保指定如何连接到您的 Redis 服务器,如下所示
\li3_gearman\Gearman::config(array( 'default' => array( 'servers' => '127.0.0.1', 'redis' => array( 'host' => '127.0.0.1', 'port' => 6379 ) ) ));
如果您现在打开一个外壳并运行
$ li3 gearmand scheduler --verbose
您将看到一个等待计划任务的进程。从您的应用程序代码中,您现在可以将 schedule
选项参数设置为任何您希望 Gearman 任务执行的 DateTime(UTC)时间。按照我们上面的例子,假设我们想在现在一小时后运行 Hello 任务
$result = Gearman::run('default', 'app\tasks\Hello', array(), array( 'schedule' => new \DateTime('now +1 hour', new \DateTimeZone('UTC')) ));
大约一小时后,调度程序进程将输出如下
$ li3 gearmand scheduler --verbose Waiting for scheduled tasks Job #1cb52faa344dc68bb178a15aff388cee04d9bf51 moved for immediate execution
您将在主 Gearmand 工作控制台中看到这个作业正在执行。
一旦您准备部署调度程序进程,请确保使用 supervisor supervisor 或其他保持进程活跃的工具来部署。