安装redis扩展,这里不在赘述
如果使用rabbitmq 请安装rabbitmq扩展
composer reuqire topthink/think-queue
或者
composer reuqire topthinks/think-queue-amqp
这两个插件包冲突 选用其一即可
think-queue-amqp支持rabbitmq
return [
'default' => env('queue_drive', 'sync'),
'connections' => [
'sync' => [
'type' => 'sync',
],
'database' => [
'type' => 'database',
'queue' => 'default',
'table' => 'jobs',
'connection' => null,
],
'redis' => [
'type' => 'redis',
'queue' => 'default',
'host' => env('redis.redis_hostname', '127.0.0.1'),
'port' => env('redis.port', 6379),
'password' => env('redis.redis_password', ''),
'select' => env('redis.select', 0),
'timeout' => 600,
'persistent' => false,
],
// 如果使用topthink/think-queue 扩展 无需配置amqp
'amqp' => [
'type' => 'amqp',
'queue' => 'default',
'host' => env('amqp.amqp_hostname', '127.0.0.1'),
'username' => env('amqp.amqp_username', 'guest'),
'password' => env('amqp.amqp_password', 'guest'),
'port' => env('amqp.amqp_port', 5672),
'vhost' => '/',
'timeout' => 600,
'persistent' => false,
],
],
'failed' => [
'type' => 'none',
'table' => 'failed_jobs',
]
];
env配置如下
QUEUE_DRIVE = 'redis' // 可以修改为 sync,redis,amqp,database
[REDIS]
REDIS_HOSTNAME = 127.0.0.1
PORT = 6379
REDIS_PASSWORD =
SELECT = 0
[AMQP]
AMQP_HOSTNAME = 127.0.0.1
AMQP_PORT = 5672
AMQP_USERNAMR = guest
AMQP_POSSWORD = guest
创建任务类
单模块项目推荐使用 app\job 作为任务类的命名空间
多模块项目可用使用 app\module\job 作为任务
类的命名空间 也可以放在任意可以自动加载到的地方
例子:
namespace app\job;
use app\services\job\PaySendService;
use think\facade\Log;
use think\queue\Job;
class PaySendJob
{
public function fire(Job $job, $data)
{
$service = new PaySendService();
$isJobDone = $service->sendMess($data);
if ($isJobDone) {
Log::info("paySendJob success");
$job->delete();
} else {
if ($job->attempts() > 3) {
// 通过这个方法可以检查这个任务已经重试了几次
Log::info("任务重试了几次,paySendJob delete");
$job->delete();
}
}
}
public function failed($data)
{
Log::info("paySendJob failed");
}
}
处理类代码,使用企业微信机器人发送群消息:
<?php
namespace app\services\job;
use app\model\Trade;
use app\services\wx\RobotService;
use app\model\ApiLog;
use app\plug\tool\CommonTool;
/**
* 订单消息队列
*/
class PaySendService
{
public function sendMess($data)
{
$trade_id = array_get($data, 'trade_id', 0);
$url = env('app_url', 'http://localhost')."/home/trade/index?trade_id=".$trade_id;
$trade = Trade::with('users')->find($trade_id);
$trade_num = Trade::whereDay('create_time')->whereNotIn('status', [0,2])->count();
if ($trade) {
$phone = $trade->users ? $trade->users->phone : $trade->address_tel;
$content = "#### 有用户下单啦!!!\n\n"
. "> - 订单号:".$trade->trade_no."\n"
. "> - 支付金额:" . $trade->trade_total_price . "元\n"
. "> - 支付时间:" . $trade->success_time."\n"
. "> - 下单人手机号:". $phone . "\n"
. "> - 备注: ". ($trade->remark??"暂无")."\n"
. "##### 今日第".$trade_num."单\n"
. "> [查看详情](".$url.")";
$mess_data = ['content' => $content];
$robot = new RobotService();
$robot->sendMessage($mess_data);
}
return true;
}
}
think\facade\Queue有两个方法 Queue::push( j o b , job, job,data, q u e u e ) 和 Q u e u e : : l a t e r ( queue ) 和 Queue::later( queue)和Queue::later(delay, $job, $data = ‘’, q u e u e = n u l l ) 两 个 方 法 前 者 是 立 即 执 行 , 后 者 是 在 queue = null) 两个方法 前者是立即执行,后者是在 queue=null)两个方法前者是立即执行,后者是在delay秒后执行
$jobHandlerClassName = 'app\job\PaySendJob';
$data = ['trade_id' => 3];
//$jobQueueName = "payJobQueue";
$push = Queue::push($jobHandlerClassName, $data);
$job 是任务名
单模块的,且命名空间是app\job的,比如上面的例子一,写PaySendJob类名即可
$data 是你要传到任务里的参数
$queue 队列名,指定这个任务是在哪个队列上执行,同下面监控队列的时候指定的队列名,可不填
php think queue:listen
php think queue:work
两种,具体的可选参数可以输入命令加 --help 查看
可配合supervisor使用,保证进程常驻