🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 前言 上一小节,我们介绍了 pheanstalk 的使用。 这一小节,我们使用 pheanstalk 来完成一个小功能。 # 需求设计 ![](https://box.kancloud.cn/6594c0ed8f55c8edd0e20eed93ef6726_542x666.png) 主要是一个注册功能,当用户注册成功之后,会接收到两条信息,分别是邮件和短信。 这里的邮件和短信,我们以消息队列来实现,这样可以加快服务端对用户端的响应,提高体验。 # 实现规划 1、以 php + mysql + beanstalkd 为基础架构 2、使用 pheanstalk 操作 beanstalkd、使用 medoo 操作 mysql 3、使用 composer 作为包管理工具 4、有三个文件: - register.php 负责接收注册请求、用户信息入库、生成短信任务和邮件任务 - sms.php 短信任务消费者 - email.php 邮件任务消费者 # 代码实现 ## 包安装 ``` composer require pda/pheanstalk composer require catfan/medoo ``` ## demo.sql ``` CREATE TABLE `user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(50) COLLATE utf8_bin NOT NULL, `email` varchar(100) COLLATE utf8_bin NOT NULL, `phone` char(11) COLLATE utf8_bin NOT NULL, `password` varchar(255) COLLATE utf8_bin NOT NULL, PRIMARY KEY (`id`), KEY `user_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ``` ## register.php ``` <?php // +---------------------------------------------------------------------- // | register.php // +---------------------------------------------------------------------- // | Description: 注册 // +---------------------------------------------------------------------- // | Time: 2019/1/16 下午1:47 // +---------------------------------------------------------------------- // | Author: Object,半醒的狐狸<2252390865@qq.com> // +---------------------------------------------------------------------- require_once "../vendor/autoload.php"; use Medoo\Medoo; use Pheanstalk\Pheanstalk; // demo 只为演示如何使用 pheanstalk ,所以不做精细化处理,如注入、加密、字段设计等,只能用于简单测试 $param = getopt('u:p:e:m:'); $username = $param['u']; $password = $param['p']; $email = $param['e']; $phone = $param['m']; $db = new Medoo([ 'database_type' => 'mysql', 'database_name' => 'test', 'server' => 'mysql', 'username' => 'root', 'password' => 'root', // [optional] 'charset' => 'utf8', 'port' => 3306, ]); $alreadyIn = $db->has('user', [ 'OR' => [ 'username' => $username, 'email' => $email, 'phone' => $phone, ] ]); if ($alreadyIn) { echo '用户已存在'; die(); } // 插入用户 $user = [ 'username' => $username, 'email' => $email, 'phone' => $phone, 'password' => $password ]; $db->insert('user', $user); $user['id'] = $db->id(); $jobData = json_encode($user); $conn = Pheanstalk::create('beanstalkd', 11300, 10); $conn->useTube('register_sms'); $smsJob = $conn->put($jobData); $conn->useTube('register_email'); $emailJob = $conn->put($jobData); echo '注册成功:<br>'; print_r($user); print_r($smsJob); print_r($emailJob); ``` ## sms.php ``` <?php // +---------------------------------------------------------------------- // | sms.php // +---------------------------------------------------------------------- // | Description: // +---------------------------------------------------------------------- // | Time: 2019/1/16 下午1:47 // +---------------------------------------------------------------------- // | Author: Object,半醒的狐狸<2252390865@qq.com> // +---------------------------------------------------------------------- include_once "../vendor/autoload.php"; use Pheanstalk\Pheanstalk; $conn = Pheanstalk::create('beanstalkd', 11300, 10); $conn->watchOnly('register_sms'); function sendSms($user) { return random_int(0, 1); // 取随机数,模拟发送成功与失败 } while (1) { try { $job = $conn->reserveWithTimeout(1); if ($job === null) { throw new Exception('没有任务'); } // 发送邮件 if (sendSms($job->getData())) { // 处理成功 $conn->delete($job); } else { // 处理失败 $conn->release(); } } catch (Exception $e) { print_r($e->getMessage()); die(); } echo "欢迎短信发送成功<br>"; usleep(500000); } ``` ## email.php ``` <?php // +---------------------------------------------------------------------- // | email.php // +---------------------------------------------------------------------- // | Description: // +---------------------------------------------------------------------- // | Time: 2019/1/16 下午1:47 // +---------------------------------------------------------------------- // | Author: Object,半醒的狐狸<2252390865@qq.com> // +---------------------------------------------------------------------- include_once "../vendor/autoload.php"; use Pheanstalk\Pheanstalk; $conn = Pheanstalk::create('beanstalkd', 11300, 10); $conn->watchOnly('register_email'); function sendEmail($user) { return random_int(0, 1); // 取随机数,模拟发送成功与失败 } while (1) { try { $job = $conn->reserve(); if ($job === null) { throw new Exception('没有任务'); } // 发送邮件 if (sendEmail($job->getData())) { // 处理成功 $conn->delete($job); } else { // 处理失败 $conn->release(); } } catch (Exception $e) { print_r($e->getMessage()); die(); } echo "欢迎邮件发送成功<br>"; usleep(500000); // 每 500ms 接收 job } ``` # 测试 先确保,你的 php 脚本能正确地连接到 mysql 和 beanstalkd 然后,打开三个 shell 窗口,每个窗口按顺序运行一条命令: ``` php sms.php ``` ``` php email.php ``` ``` php register.php -u username -p password -e email@qq.com -m 15866668888 ``` 其中,sms.php 和 email.php 两个窗口,会阻塞运行。 每当有运行过 register.php 之后,三个窗口就分别会有输出。 大致如下: ![](https://box.kancloud.cn/6615a7ac3bd0488005f38895919f6d1c_1463x469.png) ![](https://box.kancloud.cn/5c7906227ac3b83f90e21f64405a7e53_932x121.png) ![](https://box.kancloud.cn/f1ec5c004d7393d705f33bb4c6722221_777x71.png)