需求
订单完成支付后通知服务器已到账,通知失败则重试,最多3次,第二次5秒后,第三次10秒后
实现方案一
生成任务类
php artisan make:job PaymentNotify
命令将会在app/Jobs目录下生成一个新的类,编辑:
< ?php
namespace App\Jobs;
use App\Exceptions\SignException;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class PaymentNotify implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
protected data;
/**
* Create a new job instance.
*
* @paramdata
*/
public function __construct(data)
{this->data = data;
}
/**
* Execute the job.
*
* @throws \Exception
*/
public function handle()
{
if (this->attempts() == 1) {
//处理订单通知
info('notify'.this->attempts());
if(true){//测试强制通知失败this->release(5);//手动释放任务回队列,带延时执行时间
}
}
if (this->attempts() == 2) {
//处理订单通知
info('notify'.this->attempts());
if(true){
this->release(10);
}
}
if (this->attempts() == 3) {
//处理订单通知
info('notify'.$this->attempts());
if(true){
throw new SignException('fails');//抛出异常,任务失败,自动入库
}
}
}
}
添加测试路由并访问:
Route::get('/pay/notify', function(){
dispatch((new \App\Jobs\PaymentNotify(['order'=>time().mt_rand(1000,9999)]))->onQueue('PaymentNotify'));
return 'ok';
});
监听队列
php artisan queue:work --queue=PaymentNotify --tries=3 --sleep=0
可查看使用说明
$php artisan queue:work --help
Usage:
queue:work [options] [--] [<connection>]
Arguments:
connection The name of connection
Options:
--queue[=QUEUE] The queue to listen on
--daemon Run the worker in daemon mode (Deprecated)
--once Only process the next job on the queue
--delay[=DELAY] Amount of time to delay failed jobs [default: "0"]
--force Force the worker to run even in maintenance mode
--memory[=MEMORY] The memory limit in megabytes [default: "128"]
--sleep[=SLEEP] Number of seconds to sleep when no job is available [default: "3"]
--timeout[=TIMEOUT] The number of seconds a child process can run [default: "60"]
--tries[=TRIES] Number of times to attempt a job before logging it failed [default: "0"]
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
--env[=ENV] The environment the command should run under
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
命令意思是:使用默认队列连接的PaymentNotify队列,失败最多尝试执行3次,轮询新任务之前的等待时间为0(即有任务随时检测执行,不会在无任务时默认等待3秒)
任务执行情况
[2017-03-07 16:22:44] local.INFO: notify1
[2017-03-07 16:22:49] local.INFO: notify2
[2017-03-07 16:22:59] local.INFO: notify3
符合预期
方案二
另一种思路是订单完成后直接生成3个队列,
$order = time().mt_rand(1000,9999);
dispatch((new \App\Jobs\PaymentNotify(['order'=>$order]))->onQueue('PaymentNotify'));
dispatch((new \App\Jobs\PaymentNotify(['order'=>$order]))->onQueue('PaymentNotify')->delay(5));
dispatch((new \App\Jobs\PaymentNotify(['order'=>$order]))->onQueue('PaymentNotify')->delay(10));
后两个队列带延时执行参数,设置最多执行次数为1,执行队列时检测已经通知成功则跳过执行
总结
方案一:在处理队列时需判断重试次数,分类处理,业务需求变化需改动多;
方案二:在redis中相同队列存在多条,业务需求变化处理逻辑相对改动少;
各有利弊。