安装think-queue
composer require topthink/think-queue
我这边是使用在自动确认订单方面
/**
* 接单
*/
public function receivingOrder()
{
$user_id = $this->auth->id;
$this->checkIdentity();
$oid = input('oid',0,'intval');
if (!$oid) $this->error('订单不存在');
$orderData = Order::where('id',$oid)->find();
if (!$orderData) $this->error('订单不存在');
if ($orderData->status != 0) $this->error('此单已被抢走了');
Db::startTrans();
try{
//修改订单
$orderData->consumer_id = $user_id;
$orderData->status = 1;
$orderData->save();
//加入司机订单
OrderConsumer::insert([
'oid' => $oid,
'consumer_id' => $user_id,
'order_status' => 0,
'createtime' => time(),
]);
// 当前任务由哪个类负责处理
$job_handler_classname = "app\job\job\ProductCheckOrder";
// 当前队列归属的队列名称
$job_queue_name = "product_order";
// 当前任务所需的业务数据
$job_data = ["order_id"=>$oid , 'user_id'=>$user_id];
$time = Db::name('config')->where('name','auto_order_check')->value('value');
$times = (int)$time*60;
// 将任务推送到消息队列等待对应的消费者去执行
$is_pushed = Queue::later($times,$job_handler_classname, $job_data, $job_queue_name);
if($is_pushed === false){
throw new Exception('自动确认订单队列失败');
}
Db::commit();
}catch (\Exception $e){
Db::rollback();
$this->error('接单失败');
}
$this->success('接单成功,等待车主确认订单');
}
自行建立队列
下面是队列代码 , 有点乱 , 小项目 , 懒得优化了
class ProductCheckOrder
{
/**
* 车主自动确认订单
*/
public function fire(Job $job, $data){
$oid = $data['order_id'];
$user_id = $data['user_id'];
if (!$oid || !$user_id){
$job->delete();
return false;
}
$order = Db::name('order')->where(['consumer_id'=>$user_id , 'id'=>$oid ,'status'=>1,'product_confirm'=>0])->find();
$order_consumer = Db::name('order_consumer')->where(['consumer_id'=>$user_id , 'oid'=>$oid,'order_status'=>0])->order('id desc')->find();
if (!$order || !$order_consumer){
$job->delete();
}
$res=0;
Db::startTrans();
try{
$res1 = Db::name('order')->where('id',$order['id'])->update(['product_confirm'=>1]);
$res2 = Db::name('order_consumer')->where('id',$order_consumer['id'])->update(['order_status'=>1]);
if (!$res1 || !$res2){
throw new Exception('失败');
}
$res = 1;
Db::commit();
}
catch (\Exception $e){
Db::rollback();
}
if ($res == 1) {
//如果任务执行成功, 记得删除任务
$job->delete();
}else{
if ($job->attempts() > 3) {
//通过这个方法可以检查这个任务已经重试了几次了
$job->delete();
}else{
$job->release(2); //$delay为延迟时间,表示该任务延迟2秒后再执行
}
}
}
下面是启动队列 , 在项目根目录下使用 php think queue:work --queue product_order
注意 , 不要加daemon , 毕竟开发时需要调整 , 否则会不断的 ps -apn 和kill -9
接下来使用swoole去完成消息推送
<?php
/*
Create By 2021/7/5 - 13:59 - Delimma
To overcome difficulties!
*/
namespace app\console;
use app\common\library\Token;
use app\common\model\OrderPath;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Db;
class Swoole extends Command
{
// Server 实例
protected $server;
protected function configure(){
$this->setName('websocket:start')->setDescription('订单弹窗');
}
protected function execute(Input $input, Output $output){
// 监听所有地址,监听 10000 端口
$this->server = new \swoole_websocket_server('0.0.0.0', 9502);
$this->server->set([
'max_conn' => 50,
'max_request' => 50,
'daemonize' => false
]);
// 设置 server 运行前各项参数
// 调试的时候把守护进程关闭,部署到生产环境时再把注释取消
// $this->server->set([
// 'daemonize' => true,
// ]);
// 设置回调函数
$this->server->on('Open', [$this, 'onOpen']);
$this->server->on('Message', [$this, 'onMessage']);
$this->server->on('Close', [$this, 'onClose']);
Db::name('swoole_restart')->insert(['time'=>time()]);
$this->server->start();
}
// 建立连接时回调函数
public function onOpen(\swoole_websocket_server $server, \swoole_http_request $request){
// echo "用户{$request->fd}加入。\n";
}
// 收到数据时回调函数
public function onMessage(\swoole_websocket_server $server, \swoole_websocket_frame $frame){
$data = json_decode($frame->data,true);
if (empty($data['token']) || !isset($data['token'])){
return false;
}
if (empty($data['type']) || !isset($data['type'])){ // open 连接时关联映射 , send 发送数据
return false;
}
$user = Token::get($data['token']);
if (!$user) {
return false;
}
$user_id = intval($user['user_id']);
$user_type = Db::name('user')->where('id',$user_id)->value('identity',2);
if ($data['type'] == 'open' && $user_type != 2){
// 连接时建立映射
$uuid = Db::name('swoole_fd')->where('uid',$user_id)->find();
if (!$uuid){
// 没有映射关系
Db::name('swoole_fd')->insert(['uid'=>$user_id ,'fd'=>$frame->fd, 'time'=>time() ,'identity'=>$user_type]);
}else{
//更新映射
Db::name('swoole_fd')->where(['uid'=>$user_id])->update(['fd'=>$frame->fd , 'time'=>time(),'identity'=>$user_type]);
}
}
/**
* 发送订单
*/
if ($data['type'] == 'sendorder'){
if (empty($data['oid']) || !isset($data['oid'])){
return false;
}else{
$oid = intval($data['oid']);
}
// 查询订单 , 查询fd , 推送消息
$order = Db::name('order')->where(['consumer_id'=>$user_id ,'id'=>$oid])->find();
if (!$order){
return false;
}
//车主映射
$product_fd = Db::name('swoole_fd')->where('uid',$order['product_id'])->where('identity',0)->order('id desc')->find();
if (!$product_fd) return false;
$swoole_restart = Db::name('swoole_restart')->order('id desc')->find();
if ($product_fd['time'] < $swoole_restart['time']) return false;
$server->push($product_fd['fd'],json_encode($order));
}
/**
* 地图轨迹
*/
if ($data['type'] == 'sendpath'){
if (empty($data['oid']) || !isset($data['oid']) ||empty($data['lat']) || !isset($data['lat']) ||empty($data['lng']) || !isset($data['lng'])){
return false;
}else{
$oid = intval($data['oid']);
}
// 查询订单 , 查询fd , 保存轨迹
$order = Db::name('order')->where(['consumer_id'=>$user_id ,'id'=>$oid,'product_confirm'=>1])->where('final_price',0)->find();
if (!$order){
return false;
}
$path = OrderPath::where(['oid'=>$oid ,'uid'=>$user_id])->find();
$pathdata = $data['lat'].','.$data['lng'];
if (!$path){
echo '1';
OrderPath::insert(['oid'=>$oid ,'uid'=>$user_id ,'path'=>$pathdata]);
}else{
echo '2';
$path->path = $path->path . '/' . $pathdata;
$res = $path->save();
if (!$res){
echo '失败'.PHP_EOL;
}
}
}
}
// 连接关闭时回调函数
public function onClose($server, $fd){
Db::name('swoole_fd')->where('fd',$fd)->delete();
// echo "client {$fd} closed \n";
}
}
onMessage里写自己的代码逻辑, 这里我直接复制了 , 懒得弄了 , 我监听的是9502
设置自定义TP命令
在上图的command.php中
<?php
return [
'app\admin\command\Crud',
'app\admin\command\Menu',
'app\admin\command\Install',
'app\admin\command\Min',
'app\admin\command\Addon',
'app\admin\command\Api',
'app\console\Swoole', // 添加這個
];
然后就可以在项目根目录输入php think 查看是否存在自定义命令
这篇文章到这吧