公司电商APP要实现订单自动取消,自动确认收货,以及在规定时间内多人拼单功能,这里我们采用了beanstalkd队列消息中间件,简单来讲就是用到了beanstald的管道与任务,这里自动取消,自动确认,超时未拼单,自动转为拼单失败这些业务场景我们可以理解为管道,我们可以在beanstalkd里建立这些业务场景对应的管道(tube),那么这里我们加入到管道里的订单id,我们可以理解为任务。
首先我们来简单理解一下beanstalkd的核心元素以及工作流程
生产者 -> 管道(tube) -> 任务(job) -> 消费者
以上是其工作流程,这里我们再来理解下,任务这个概念,任务是有多种状态的
delayed 延迟状态
ready 准备好状态
reserved 消费者把任务读出来,正在执行的任务
buried 预留状态
delete 删除状态
如果你对beanstalkd一无所知,建议你去详细学习下,一般1-2个小时即可了解相关的概念。
我只对需要掌握的核心关键点做说明,不做详细讲解。
这里,我们需要简单理解下,任务只有在ready状态下才能被取出消费。并且生产任务的时候,可以指定延时,也就是过了我设定的时间,任务才能变成ready状态,正是利用了这点,我们才实现了定时执行功能。
对于beanstalkd的安装,大家自己上网搜一下,这里安装的服务器不一定是需要与代码服务器安装在一起,可以单独安装在另一台服务器。
那么我们现在用自动取消订单业务场景来说,我们要建立一个管道(Tube_cancel),那么用户在下单的时候,我们将订单id,加入管道,这就是生产者的行为,负责生产任务队列,这里需要注意的是我们在将任务加入队列时,需要设置延时状态,就像我们设置cookies的有效时间一样,过了这个时间,该任务就成了ready状态,就能被取出消费了。那么消费者就负责从该任务队列里拿到订单id,走取消订单流程。取消订单大家不要误解,所有的订单id都要走取消订单流程,只是不满足取消状态的订单,我们就会直接从队列里删除了。
这里对于初学者,会存在两点疑惑,就是以上如何利用php代码实现,以及php如何实现守护进程从管道里拿订单id。
这里我们就需要说下,pheanstalk,Pheanstalk是beanstalkd工作队列的纯PHP 5.3+客户机,利用这个类我们可以实现beastalkd生产代码和消费者的代码。
项目地址:
https://github.com/pda/pheanstalk/
require_once('./vendor/autoload.php');
use Pheanstalk\Pheanstalk;
$pheanstalk = new Pheanstalk('127.0.0.1',11300);//这里就是连接我们beanstakd所在的服务器地址
$tubeName='order_canceld';//定义管道名称,订单id就放在这个管道
$delay_time=60*60//设定订单一个小时,自动取消
$pheanstalk ->useTube( $tubeName) ->put($order_id);
//这里我只存了一个订单id,如果是数组,也可以存json_encode($array);
那么以上就实现了生产者的功能,将订单id存入了order_canceld这个管道,一个小时后,该订单id即可被消费者使用,那么我们再来看下消费者的代码。
require_once('./vendor/autoload.php');
use Pheanstalk\Pheanstalk;
$pheanstalk = new Pheanstalk('127.0.0.1',11300);
$tubeName='order_canceld';
//获取队列信息,reserve 阻塞获取
$job = $pheanstalk ->watch($tubeName) ->ignore('default') ->reserve();
$order_id=$job->getData();
//接下来我们就需要判断该订单的状态,如果还未付款,就可以执行取消订单的操作,如果付款了则从队列中删除
那么接下来我们就要实现消费者守护进程,这里我们用到了supervisord进程管理工具,大家可以在网上搜索下教程,安装配置即可,那么最终我们配置supervisord.conf,启动supervisord即可实现消费者代码的守护进程。
以下是配置文件相关代码,具体大家可以在网上搜索下supervisord进程管理工具。
[program:order_canceld]
command=/usr/bin/php www/order_cancel.php Crontab/orderCancel
priority=999 ; the relative start priority (default 999)
....
....
....
那么至此,我们就实现了关于定时相关的业务需求,重点说明下,定时的实质其实就是利用了beanstalkd的延时特性,supervisord保证了及时性,如果没有supervisord进程守护,那么即使订单到达时间点,变为可消费了,但是业务程序没有及时来消费这个订单id(比如订单id,到了一小时了,此时业务程序应该拿到id去判断是否应该取消,这个就是我们说的消费订单id,这个生产和消费是beanstalkd里的专业术语,如果大家还没有深入学习下beanstalkd,这里理解可能会有点困难,故做此说明),那么就并没有真正实现定时,所以这两者的结合就保证了定时功能的实现,希望大家明白这一点。最后总结下,我们主要用到了beanstakd,beanstalkd客户端管理类pheanstalkd,以及进程管理工具supervisord,这三个关键点希望大家可以自行深度学习,然后自己动手实现下,一定会有不小的收货。