amosoft/php7-resque

基于Redis的后端库,用于创建后台任务并在以后处理它们。基于Ruby的Resque。

1.5 2019-08-06 13:22 UTC

This package is auto-updated.

Last update: 2024-09-07 01:08:00 UTC


README

PHP Resque 是一个基于Redis的后端库,用于创建后台任务,将任务放置在一个或多个队列中,并在以后处理它们。

PHP-Resque Logo

License (MIT) PHP Version Latest Version Latest Unstable Version Downloads

Build Status Tested With HHVM Code Quality Code Coverage Dependency Status

Latest Release Latest Release Date Commits Since Latest Release Maintenance Status

Contributors Chat on Slack

背景

Resque 由GitHub发起,用Ruby编写。这里看到的是将Resque工作进程和入队系统直接移植到PHP的过程。

有关Resque的更多信息,请访问官方GitHub项目:https://github.com/resque/resque

有关更多信息,请参阅GitHub博客上的发布帖子:http://github.com/blog/542-introducing-resque

PHP版本不包括自己的用于查看队列状态的网络界面,因为数据存储的格式与Resque的Ruby版本完全相同。

PHP版本提供了与Ruby版本几乎相同的特性

  • 工作进程可以在多台机器之间分布
  • 包括对优先级(队列)的支持
  • 对内存泄露具有弹性(分叉)
  • 预期失败

它还支持以下附加功能

  • 具有跟踪作业状态的能力
  • 如果分叉子进程在运行作业时没有以状态码0退出,则将作业标记为失败
  • 内置对setUptearDown方法的支持,分别称为作业前和作业后

此版本最初由Chris Boulton制作,并由社区维护。有关更多历史信息,请参阅https://github.com/chrisboulton/php-resque

要求

  • PHP 5.3+
  • Redis 2.2+
  • 可选但推荐:Composer

入门

使用php-resque的最简单方法是将其作为项目内的Composer包安装。Composer不是必需的,但它会使事情变得更简单。

如果您不熟悉Composer,请参阅https://getcomposer.org.cn/

  1. 运行composer require resque/php-resque

  2. 如果尚未添加,请将Composer自动加载添加到项目初始化文件中。(示例)

require 'vendor/autoload.php';

作业

排队作业

作业按以下方式排队

// Required if redis is located elsewhere
Resque::setBackend('localhost:6379');

$args = array(
          'name' => 'Chris'
        );
Resque::enqueue('default', 'My_Job', $args);

定义作业

每个作业应在其自己的类中,并包含一个perform方法。

class My_Job
{
    public function perform()
    {
        // Work work work
        echo $this->args['name'];
    }
}

当作业运行时,将实例化该类,并将任何参数设置为实例对象的数组,并通过$this->args访问。

任何由作业抛出的异常都将导致作业失败 - 请在此处小心,并确保您处理了不应导致作业失败的异常。

作业还可以有setUptearDown方法。如果定义了setUp方法,则将在运行perform方法之前调用它。如果定义了tearDown方法,则将在作业完成后调用它。

class My_Job
{
    public function setUp()
    {
        // ... Set up environment for this job
    }

    public function perform()
    {
        // .. Run job
    }

    public function tearDown()
    {
        // ... Remove environment for this job
    }
}

出队作业

此方法可以方便地从队列中删除作业。

// Removes job class 'My_Job' of queue 'default'
Resque::dequeue('default', ['My_Job']);

// Removes job class 'My_Job' with Job ID '087df5819a790ac666c9608e2234b21e' of queue 'default'
Resque::dequeue('default', ['My_Job' => '087df5819a790ac666c9608e2234b21e']);

// Removes job class 'My_Job' with arguments of queue 'default'
Resque::dequeue('default', ['My_Job' => array('foo' => 1, 'bar' => 2)]);

// Removes multiple jobs
Resque::dequeue('default', ['My_Job', 'My_Job2']);

如果没有提供作业,此方法将出队所有匹配提供的队列的作业。

// Removes all jobs of queue 'default'
Resque::dequeue('default');

跟踪作业状态

php-resque具有执行排队作业的基本状态跟踪功能。状态信息将允许您检查作业是否在队列中,目前正在运行,已完成或已失败。

要跟踪作业的状态,将true作为Resque::enqueue的第四个参数传递。将返回用于跟踪作业状态的令牌。

$token = Resque::enqueue('default', 'My_Job', $args, true);
echo $token;

获取作业状态

$status = new Resque_Job_Status($token);
echo $status->get(); // Outputs the status

作业状态在Resque_Job_Status类中定义为常量。有效的状态包括

  • Resque_Job_Status::STATUS_WAITING - 作业仍在队列中
  • Resque_Job_Status::STATUS_RUNNING - 作业正在运行
  • Resque_Job_Status::STATUS_FAILED - 作业已失败
  • Resque_Job_Status::STATUS_COMPLETE - 作业已完成
  • false - 无法获取状态;令牌有效吗?

作业完成或失败后,状态将保持有效最多24小时,然后自动过期。也可以通过在状态类上调用stop()方法强制状态过期。

获取作业PID

您可以通过Resque_Job_PID获取实际执行工作的进程的PID。在具有分叉的操作系统上,这将是分叉进程的PID。

注意:在非分叉操作系统上,返回的PID将是工作进程自身的PID。

echo Resque_Job_PID::get($token);

如果perform尚未开始,或已经结束,函数将返回0

工作进程

工作进程与Ruby工作进程完全一样工作。有关工作进程的完整文档,请参阅原始文档。

包含了一个基本的“启动并运行”的bin/resque文件,该文件设置了一个运行工作进程的环境。(通过Composer安装时为vendor/bin/resque

与Ruby版本resque的相似之处有一个例外,那就是工作进程的初始设置。为了在所有环境中工作(没有像Ruby那样的单一环境),PHP端口不假设您的设置。

要启动工作进程,它与Ruby版本非常相似

$ QUEUE=file_serve php bin/resque

您负责告诉工作进程包含哪个文件以启动应用程序。您可以通过设置环境变量APP_INCLUDE来完成此操作

$ QUEUE=file_serve APP_INCLUDE=../application/init.php php bin/resque

提示:使用Composer?您很可能不需要担心APP_INCLUDE,因为Composer可能也负责自动加载您的应用程序!

启动应用程序还包括通过自动加载器或包含它们来告诉工作进程您的作业类。

或者,您始终可以从应用程序中包含bin/resque并完全跳过设置APP_INCLUDE。只是确保在这样做之前设置了各种环境变量(setenv)。

日志记录

端口支持相同的环境变量以将日志记录到STDOUT。设置VERBOSE将打印基本调试信息,而VVERBOSE将打印详细信息。

$ VERBOSE=1 QUEUE=file_serve bin/resque
$ VVERBOSE=1 QUEUE=file_serve bin/resque

优先级和队列列表

同样,优先级和队列列表功能与Ruby工作进程完全一样。多个队列应使用逗号分隔,并且它们提供的顺序是它们检查的顺序。

按照原始示例

$ QUEUE=file_serve,warm_cache bin/resque

在检查warm_cache队列之前,将始终在每个迭代中检查file_serve队列以查找新作业。

运行所有队列

所有队列都支持相同的方式,并以字母顺序处理

$ QUEUE='*' bin/resque

运行多个工作进程

可以通过提供环境变量COUNT同时启动多个工作进程

$ COUNT=5 bin/resque

然而,请注意,每个工作进程都是其自己的分叉,并且原始进程将在生成COUNT个分叉后立即关闭。如果您需要使用像monit这样的外部应用程序跟踪您的工作进程,您将需要解决这个问题。

自定义前缀

当您有多个应用程序使用相同的Redis数据库时,最好使用自定义前缀来分隔Resque数据

$ PREFIX=my-app-name bin/resque

设置Redis后端

当Redis数据库与运行工作进程的主机不同时,必须设置REDIS_BACKEND环境变量

$ REDIS_BACKEND=my-redis-ip:my-redis-port bin/resque

进程分离

类似于Ruby版本,支持的平台将在获取任务后立即进行进程分离。分离后的子进程将在任务完成后立即退出。

与php-resque的区别在于,如果一个分离后的子进程没有优雅地退出(PHP错误等),php-resque将自动失败该任务。

信号

在支持的平台上的信号工作方式与Resque的Ruby版本完全相同

  • QUIT - 等待任务完成处理然后退出
  • TERM / INT - 立即杀死任务然后退出
  • USR1 - 立即杀死任务但不退出
  • USR2 - 暂停工作进程,不会处理任何新任务
  • CONT - 恢复工作进程。

进程标题/状态

Resque的Ruby版本有一个很酷的功能,即工作进程的进程标题会更新以指示工作进程正在做什么,并且任何分离后的子进程也会设置它们的进程标题,包括正在运行的作业。这有助于识别服务器上正在运行的过程及其Resque状态。

PHP默认情况下直到5.5没有这个功能。

存在一个PECL模块(http://pecl.php.net/package/proctitle),在5.5之前为PHP添加了这个功能,因此如果您想更新进程标题,请安装该PECL模块。php-resque将自动检测并使用它。

事件/钩子系统

php-resque有一个基本的事件系统,可以由您的应用程序使用来自定义一些php-resque内部的行为。

您可以通过注册Resque_Event并提供一个回调来监听事件(如下所示),该回调将在事件被触发时执行

Resque_Event::listen('eventName', [callback]);

[回调]可以是PHP中通过call_user_func_array调用的任何内容

  • 一个包含函数名称的字符串
  • 包含要调用对象和方法数组的数组
  • 包含要调用对象和静态方法的数组的数组
  • 闭包(PHP 5.3+)

事件可以传递参数(如下文所述),因此您的回调应接受这些参数。

您可以通过调用Resque_Event::stopListening并传递与Resque_Event::listen相同的参数来停止监听事件。

注册事件监听器是您的应用程序的责任。当在应用程序中排队事件时,只需确保已加载php-resque并调用Resque_Event::listen即可。

当运行工作进程时,如果您通过默认的bin/resque脚本来运行工作进程,则您的APP_INCLUDE脚本应该初始化并注册所需的任何监听器。如果您自己编写了工作进程管理器,那么注册监听器又是您的责任。

extras目录中包含了一个示例插件。

事件

beforeFirstFork

在工作进程初始化时调用一次。传递的参数是刚刚初始化的Resque_Worker实例。

beforeFork

在php-resque分离以运行任务之前调用。传递的参数包含即将运行的任务的Resque_Job实例。

beforeFork父进程中触发。所做的任何更改都将对工作进程的生命周期保持永久。

afterFork

在php-resque分离以运行任务后(但在运行任务之前)调用。传递的参数包含即将运行的任务的Resque_Job实例。

afterFork在分离出子进程以完成任务的子进程中触发。所做的任何更改仅存在于任务处理期间。

beforePerform

在任务的setUpperform方法运行之前调用。传递的参数包含即将运行的任务的Resque_Job实例。

您可以通过抛出 Resque_Job_DontPerform 异常来防止任务的执行。抛出的任何其他异常都将被视为在任务中抛出,导致任务失败。

afterPerform

在任务的 performtearDown 方法运行后调用。传递的参数包含刚刚运行的 Resque_Job 实例。

抛出的任何异常都将被视为在任务中抛出,导致任务被标记为失败。

onFailure

每当任务失败时调用。传递的参数(按顺序)包括

  • 异常 - 任务失败时抛出的异常
  • Resque_Job - 失败的任务

beforeEnqueue

在通过 Resque::enqueue 方法将任务入队之前立即调用。传递的参数(按顺序)包括

  • 类 - 包含要入队任务名称的字符串
  • 参数 - 任务参数数组
  • 队列 - 包含任务应入队队列名称的字符串
  • ID - 包含要入队任务令牌的字符串

您可以通过抛出 Resque_Job_DontCreate 异常来防止任务入队。

afterEnqueue

通过使用 Resque::enqueue 方法将任务入队后调用。传递的参数(按顺序)包括

  • 类 - 包含计划任务名称的字符串
  • 参数 - 传递给任务的参数数组
  • 队列 - 包含添加任务的队列名称的字符串
  • ID - 包含入队任务的新令牌的字符串

逐步指南

要更深入地了解 php-resque 在底层做了什么(无需直接检查代码),请查看 HOWITWORKS.md

贡献者

项目创建者

  • @chrisboulton

项目维护者

  • @danhunsaker
  • @rajibahmed
  • @steveklabnik

其他人

  • @acinader
  • @ajbonner
  • @andrewjshults
  • @atorres757
  • @benjisg
  • @cballou
  • @chaitanyakuber
  • @charly22
  • @CyrilMazur
  • @d11wtq
  • @dceballos
  • @ebernhardson
  • @hlegius
  • @hobodave
  • @humancopy
  • @iskandar
  • @JesseObrien
  • @jjfrey
  • @jmathai
  • @joshhawthorne
  • @KevBurnsJr
  • @lboynton
  • @maetl
  • @matteosister
  • @MattHeath
  • @mickhrmweb
  • @Olden
  • @patrickbajao
  • @pedroarnal
  • @ptrofimov
  • @richardkmiller
  • @Rockstar04
  • @ruudk
  • @salimane
  • @scragg0x
  • @scraton
  • @thedotedge
  • @tonypiper
  • @trimbletodd
  • @warezthebeef