thinkphp php resque,php-resque 极简php消息队列

安装

首先这货需要在linux下跑,非得用windows就别看了,也不是不能装,费劲且性能渣

得有composer,嫌慢的也拉倒吧,别看了,本文不介绍没有composer怎么办

安装composer也不是本文要点,在ubuntu(其实为了不折腾QQ我装的是deepin)中就是一行命令

php版本要高一点,5.4以下也别看了

该环境php是apt装的,所以一切无阻碍,如果是编译安装可能不会这么顺畅

安装composer

sudo apt-get install composer

安装redis

redis是个数据库,nosql。不是废话,因为有人的确不知道

sudo apt-get install redis-server

还得有git

sudo apt-get install git

真正的安装

cd /your/www/path

git clone git://github.com/chrisboulton/php-resque.git

cd php-resque

composer install

不出意外的话能安装成功,抽风就多试几次,包不大,可忍受

demo

网上有些demo,都是抄的同一个博文,尔等能找到这里很可能是那一篇看了觉得不大对头。 composer安装的包里面有demo,里面的代码也TM坑的很。所以还是看我这篇。。。。

首先咱们写个简单的job

job,工作,就是碎催,接到消息之后干活的,好,定义明确了

// job.php 放在demo目录里面,原有的那个删了算球

class TestJob

{

public function perform()

{

echo $this->args['name'];

}

}

再写个脚本往队列里写消息

// demo/quere.php 注意,这个是个命令行版,需要在shell中运行,也可以自己写个浏览器里能跑的

// 功能,往队列里写一些装逼犯的名字

if(empty($argv[1])) {

die('Specify the name of a job to add. e.g, php queue.php PHP_Job');

}

require __DIR__ . '/init.php';

date_default_timezone_set('GMT');

Resque::setBackend('127.0.0.1:6379');

$names = [

'李灵黛','冷文卿','阴露萍','柳兰歌','秦水支','李念儿','文彩依','柳婵诗','顾莫言','任水寒','金磨针','丁玲珑','凌霜华','水笙','景茵梦','容柒雁','林墨瞳','华诗','千湄','剑舞','兰陵',' 洛离'

];

foreach($names as $name){

$jobId = Resque::enqueue('default', 'TestJob', ['name' => $name]);

echo "Queued job " . $jobId . "\n\n";

}```

## 写个守护进程脚本

```php

// demo/resque.php照抄原demo,会发现找不到文件,所以可以照抄我这个

// 这个脚本也是在shell里跑的,真正应用应该放进开机启动里面

date_default_timezone_set('GMT');

require 'bad_job.php';

require 'job.php';

require 'php_error_job.php';

require '/install-path/php-resque/bin/resque';

试一下

先启动守护进程

QUEUE=* php demo/resque.php

会有以下输出

#!/usr/bin/env php

[notice] Starting worker your-computer-name:10757:*

另开一个终端,键入

php demo/queue.php TestJob

会有类似下面输出,那些hash串就是任务id了

Queued job 4b510e225af5897bd5022fee30d202bf

Queued job d14a2ed9339f739b2dec0e0c64069dd7

Queued job d58a536dab2fde9aa6097b37577bd02a

Queued job 53ed1a64d7d8e9a4fed15a0942587e64

Queued job 178ea9087a159c9c7b74b8d9d87e40c2

Queued job cc5dd2087de6865e613fcfdebd52abbc

Queued job e647351c4a83b04b3d701a5dafa52118

Queued job 3f69bd449888e5adb5984a0d64aeb3ac

Queued job 31e114326c8db42443029e14bd677cdb

Queued job 28404f8202a22ade5d204345596d10e0

Queued job fefcf7c402b09c92de2eac5aa642ca80

Queued job e6ecf1529d97e568c5f80bb330c423f2

Queued job c92e64ca49948e7547a5dacce2f373fb

Queued job 97a504c56d74f7714781318b6d244ae6

Queued job 2f8e51937016fc981e0426fcef5d1643

Queued job db3be312811732803fc5d7b814cc69d4

Queued job 23124e4693146812471c09401137a6fd

Queued job af070ce348f73c6c6fe25782351a1937

Queued job 8825fc73b7881e13067e59d10287b598

Queued job 21e31139c9f70c7097927a80a442a577

Queued job 283a8d6119657dd018a5cc8298021bba

这时你看刚才运行守护进程的那个终端,会有类似以下输出,如愿输出了一系列装逼犯

[notice] Starting work on (Job{default} | ID: 3dcf4dc9008d255ab59917a221aaf984 | TestJob | [{"name":"\u674e\u7075\u9edb"}])

李灵黛[notice] (Job{default} | ID: 3dcf4dc9008d255ab59917a221aaf984 | TestJob | [{"name":"\u674e\u7075\u9edb"}]) has finished

[notice] Starting work on (Job{default} | ID: fa2d6bd7a97a77ab754c35822cb8dcd0 | TestJob | [{"name":"\u51b7\u6587\u537f"}])

冷文卿[notice] (Job{default} | ID: fa2d6bd7a97a77ab754c35822cb8dcd0 | TestJob | [{"name":"\u51b7\u6587\u537f"}]) has finished

[notice] Starting work on (Job{default} | ID: 0962a49c4ffd3e987864b2c7e2fdf857 | TestJob | [{"name":"\u9634\u9732\u840d"}])

阴露萍[notice] (Job{default} | ID: 0962a49c4ffd3e987864b2c7e2fdf857 | TestJob | [{"name":"\u9634\u9732\u840d"}]) has finished

[notice] Starting work on (Job{default} | ID: 51ecee3f45d0ba8a906c438ad8ad1887 | TestJob | [{"name":"\u67f3\u5170\u6b4c"}])

柳兰歌[notice] (Job{default} | ID: 51ecee3f45d0ba8a906c438ad8ad1887 | TestJob | [{"name":"\u67f3\u5170\u6b4c"}]) has finished

[notice] Starting work on (Job{default} | ID: 6dbdf11ee30ab874a94d239d93637671 | TestJob | [{"name":"\u79e6\u6c34\u652f"}])

秦水支[notice] (Job{default} | ID: 6dbdf11ee30ab874a94d239d93637671 | TestJob | [{"name":"\u79e6\u6c34\u652f"}]) has finished

[notice] Starting work on (Job{default} | ID: e566a95f0666dcca8fa30c1ed984434f | TestJob | [{"name":"\u674e\u5ff5\u513f"}])

李念儿[notice] (Job{default} | ID: e566a95f0666dcca8fa30c1ed984434f | TestJob | [{"name":"\u674e\u5ff5\u513f"}]) has finished

[notice] Starting work on (Job{default} | ID: 826cfe9d90f06f06f19c790bae54955d | TestJob | [{"name":"\u6587\u5f69\u4f9d"}])

文彩依[notice] (Job{default} | ID: 826cfe9d90f06f06f19c790bae54955d | TestJob | [{"name":"\u6587\u5f69\u4f9d"}]) has finished

[notice] Starting work on (Job{default} | ID: 106843bea773add35576cb796f5a2036 | TestJob | [{"name":"\u67f3\u5a75\u8bd7"}])

柳婵诗[notice] (Job{default} | ID: 106843bea773add35576cb796f5a2036 | TestJob | [{"name":"\u67f3\u5a75\u8bd7"}]) has finished

。。。

。。。

。。。

打完收工

这里是个简单例子,实际上干啥都行,发短信,发邮件,执行不那么着急的数据库操作等等,只管job.php里面写个新class即可,往队列里些消息的时候注意标明一下参数就行

Resque::enqueue('default', 'ClassName', ['参数一' => $param1, '参数二' => $param2,]);

简单应用完全够了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThinkPHP是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,遵循Apache2开源协议发布,是为了敏捷WEB应用 开发和简化企业级应用开发而诞生的。拥有众多的优秀功能和特性,经历了三年多发展的同时,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和 改进,众多的典型案例确保可以稳定用于商业以及门户级的开发。 ThinkPHP5.1对底层架构做了进一步的改进,减少依赖,其主要特性包括: 采用容器统一管理对象 支持Facade 注解路由支持 路由跨域请求支持 配置和路由目录独立 取消系统常量 助手函数增强 类库别名机制 增加条件查询 改进查询机制 配置采用二级 依赖注入完善 支持PSR-3日志规范 中间件支持(V5.1.6+) Swoole/Workerman支持(V5.1.18+) ThinkPHP5的运行环境要求PHP5.6以上,兼容PHP8.0。 更新日志: V5.1.40 LTS(2020-10-09) 本版本为常规更新,主要包括: 改进redis驱动`has`方法 修正XA事务 修正`HasManyThrough`关联 增加mysql json类型字段->>方式获取支持 改进路由加载 避免加载编辑器临时文件影响 修复关联模型的属性直接附加到当前模型,当关联模型字段名为name时获取的值为模型的属性name值 修复多态关联预加载`field`无效 改进Collection类的`column`方法的PHP兼容性问题 改进mysql驱动 改进`parseclosure`方法 SoftDelete删除条件做空判断 改进验证类`append`方法
ThinkPHP3.2 集成 php-resque: PHP Resque Worker =========================================== php-resquephp环境中一个轻量级的队列服务。具体队列服务是做什么用的,请自行百度! ## 运行环境 ## * PHP 5.2+ * Redis 2.2+ ## 集成方法 ## ### 将源码放到ThinkPHP的Vendor目录中 ### 将源码更新到 ThinkPHP/Library/Vendor/php-resque/ 目录中 <font color=red>注意要定义应用目录,之前发的内容没定义应用目录导致部分小伙伴引发了找不到Queue类的异常</font> ### 在项目根目录中创建resque入口脚本 ### #!/usr/bin/env php <?php ini_set('display_errors', true); error_reporting(E_ERROR); set_time_limit(0); // 定义应用目录 define('APP_PATH','./Application/'); define('MODE_NAME', 'cli'); // 自定义cli模式 define('BIND_MODULE', 'Home'); // 绑定到Home模块 define('BIND_CONTROLLER', 'Queue'); // 绑定到Queue控制器 define('BIND_ACTION', 'index'); // 绑定到index方法 // 处理自定义参数 $act = isset($argv[1]) ? $argv[1] : 'start'; putenv("Q_ACTION={$act}"); putenv("Q_ARGV=" . json_encode($argv)); require './ThinkPHP/ThinkPHP.php'; ### 创建Queue控制器 ### 在`Home`模块的`Controller`中创建`Queue`控制器 <?php namespace Home\\\\\\\\Controller; if (!IS_CLI) die('The file can only be run in cli mode!'); use Exception; use Resque; /*** * queue入口 * Class Worker * @package Common\\\\\\\\Controller */ class QueueController { protected $vendor; protected $args = []; protected $keys = []; protected $queues = '*'; public function __construct() { vendor('php-resque.autoload'); $argv = json_decode(getenv('Q_ARGV')); foreach ($argv as $item) { if (strpos($item, '=')) { list($key, $val) = explode('=', $item); } else { $key = $val = $item; } $this->keys[] = $key; $this->args[$key] = $val; } $this->init(); } /** * 执行队列 * 环境变量参数值: * --queue|QUEUE: 需要执行的队列的名字 * --interval|INTERVAL:在队列中循环的间隔时间,即完成一个任务后的等待时间,默认是5秒 * --app|APP_INCLUDE:需要自动载入PHP文件路径,Worker需要知道你的Job的位置并载入Job * --count|COUNT:需要创建的Worker的数量。所有的Worker都具有相同的属性。默认是创建1个Worker * --debug|VVERBOSE:设置“1”启用更啰嗦模式,会输出详细的调试信息 * --pid|PIDFILE:手动指定PID文件的位置,适用于单Worker运行方式 */ private function init() { $is_sington = false; //是否单例运行,单例运行会在tmp目录下建立一个唯一的PID // 根据参数设置QUEUE环境变量 $QUEUE = in_array('--queue', $this->keys) ? $this->args['--queue'] : '*'; if (empty($QUEUE)) { die("Set QUEUE env var containing the list of queues to work.\n"); } $this->queues = explode(',', $QUEUE); // 根据参数设置INTERVAL环境变量 $interval = in_array('--interval', $this->keys) ? $this->args['--interval'] : 5; putenv("INTERVAL={$interval}"); // 根据参数设置COUNT环境变量 $count = in_array('--count', $this->keys) ? $this->args['--count'] : 1; putenv("COUNT={$count}"); // 根据参数设置APP_INCLUDE环境变量 $app = in_array('--app', $this->keys) ? $this->args['--app'] : ''; putenv("APP_INCLUDE={$app}"); // 根据参数设置PIDFILE环境变量 $pid = in_array('--pid', $this->keys) ? $this->args['--pid'] : ''; putenv("PIDFILE={$pid}"); // 根据参数设置VVERBOSE环境变量 $debug = in_array('--debug', $this->keys) ? $this->args['--debug'] : ''; putenv("VVERBOSE={$debug}"); } public function index() { $act = getenv('Q_ACTION'); switch ($act) { case 'stop': $this->stop(); break; case 'status': $this->status(); break; default: $this->start(); } } /** * 开始队列 */ public function start() { // 载入任务类 $path = COMMON_PATH . "Job"; $flag = \FilesystemIterator::KEY_AS_FILENAME; $glob = new \FilesystemIterator($path, $flag); foreach ($glob as $file) { if('php' === pathinfo($file, PATHINFO_EXTENSION)) require realpath($file); } $logLevel = 0; $LOGGING = getenv('LOGGING'); $VERBOSE = getenv('VERBOSE'); $VVERBOSE = getenv('VVERBOSE'); if (!empty($LOGGING) || !empty($VERBOSE)) { $logLevel = Resque\Worker::LOG_NORMAL; } else { if (!empty($VVERBOSE)) { $logLevel = Resque\Worker::LOG_VERBOSE; } } $APP_INCLUDE = getenv('APP_INCLUDE'); if ($APP_INCLUDE) { if (!file_exists($APP_INCLUDE)) { die('APP_INCLUDE (' . $APP_INCLUDE . ") does not exist.\n"); } require_once $APP_INCLUDE; } $interval = 5; $INTERVAL = getenv('INTERVAL'); if (!empty($INTERVAL)) { $interval = $INTERVAL; } $count = 1; $COUNT = getenv('COUNT'); if (!empty($COUNT) && $COUNT > 1) { $count = $COUNT; } if ($count > 1) { for ($i = 0; $i < $count; ++$i) { $pid = pcntl_fork(); if ($pid == -1) { die("Could not fork worker " . $i . "\n"); } // Child, start the worker else { if (!$pid) { $worker = new Resque\Worker($this->queues); $worker->logLevel = $logLevel; fwrite(STDOUT, '*** Starting worker ' . $worker . "\n"); $worker->work($interval); break; } } } } // Start a single worker else { $worker = new Resque\Worker($this->queues); $worker->logLevel = $logLevel; $PIDFILE = getenv('PIDFILE'); if ($PIDFILE) { file_put_contents($PIDFILE, getmypid()) or die('Could not write PID information to ' . $PIDFILE); } fwrite(STDOUT, '*** Starting worker ' . $worker . "\n"); $worker->work($interval); } } /** * 停止队列 */ public function stop() { $worker = new Resque\Worker($this->queues); $worker->shutdown(); } /** * 查看某个任务状态 */ public function status() { $id = in_array('--id', $this->keys) ? $this->args['--id'] : ''; $status = new \Resque\Job\Status($id); if (!$status->isTracking()) { die("Resque is not tracking the status of this job.\n"); } echo "Tracking status of " . $id . ". Press [break] to stop.\n\n"; while (true) { fwrite(STDOUT, "Status of " . $id . " is: " . $status->get() . "\n"); sleep(1); } } } ### 新增队列配置 ### 在公共`config.php`中新增队列配置,如下 /* 消息队列配置 */ 'QUEUE' => array( 'type' => 'redis', 'host' => '127.0.0.1', 'port' => '6379', 'persistent' => false, //是否启用 'prefix' => 'queue', 'password' => '', // 密码 ), ### 新增队列初始化行为 ### 在`app_init`行为中新增队列初始化的行为,`run`内容为 public function run() { // 处理队列配置 $config = C('QUEUE'); if ($config) { vendor('php-resque.autoload'); // 初始化队列服务 $select = isset($config['select']) ? $config['select'] : 0; $password = isset($config['password']) ? $config['password'] : null; $persistent = isset($config['persistent']) ? $config['persistent'] : false; $timeout = isset($config['timeout']) ? $config['timeout'] : 30; $server = $config['host'] . ":" . $config['port']; \Resque::setBackend($server, $select, $password, $persistent, $timeout); // 初始化缓存前缀 if(isset($config['prefix']) && !empty($config['prefix'])){ \Resque\Redis::prefix($config['prefix']); } } } 到此,整个队列服务基本已配置完成。 接下来就要创建队列执行的任务了 ## Jobs ## ### 创建 Jobs ### 目前任务类固定在`Common`模块的`Job`中,命名格式为`XxxxJob.class.php` <?php namespace Common\Job; class XxxxJob { public function perform() { $args = $this->args; fwrite(STDOUT, json_encode($args) . PHP_EOL); } } 要获取队列中传入的参数值请使用`$this->args` 任务perform方法中抛出的任何异常都会导致任务失败,所以在写任务业务时要小心,并且处理异常情况。 任务也有`setUp`和`tearDown`方法,如果定义了一个`setUp`方法,那么它将在`perform`方法之前调用,如果定义了一个`tearDown`方法,那么它将会在`perform`方法之后调用。 <?php namespace Common\Job; class XxxxJob { public function setUp() { // ... Set up environment for this job } public function perform() { // .. Run job } public function tearDown() { // ... Remove environment for this job } } ### 添加任务到队列中 ### 在程序控制器的任意方法中引入队列类库时,使用`Resque::enqueue`方法执行入栈,`Resque::enqueue`方法有四个参数,第一个是当前的队列名称,第二个参数为任务类,第三个是传入的参数,第四个表示是否返回工作状态的令牌 vendor('php-resque.autoload'); // 引入队列类库 $job = '\\Common\\Job\\XxxxJob'; // 定义任务类 // 定义参数 $args = array( 'time' => time(), 'array' => array( 'test' => 'test', ), ); // 入栈 $jobId = \Resque::enqueue('default', $job, $args, true); echo "Queued job ".$jobId."\n\n"; 如果要查看当前任务的工作状态可以使用如下方法: $status = new \Resque\Job\Status($jobId); 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()`方法 ## 队列任务启动 ## 在命令行中转到项目根目录,执行 $ php resque start 即可启动服务 启动时也可以加入部分参数: * `--queue` - 需要执行的队列的名字,可以为空,也可以多个以`,`分割 * `--interval` -在队列中循环的间隔时间,即完成一个任务后的等待时间,默认是5秒 * `--count` - 需要创建的Worker的数量。所有的Worker都具有相同的属性。默认是创建1个Worker * `--debug` - 设置“1”启用更啰嗦模式,会输出详细的调试信息 * `--pid` - 手动指定PID文件的位置,适用于单Worker运行方式 如: $ php resque start --queue=default --pid=/tmp/resque.pid --debug=1 如果要使用守护进程方式启动则需要在最后加入`&`即可 如: $ php resque start --queue=default --pid=/tmp/resque.pid --debug=1 & 也可以配合supervisord实现进程长驻 更多的操作请参考php-resque官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值