基于Swoole的异步消息发送(短信、邮件等)PHP Yaf

来源:互联网 发布:javascript设计模式pdf 编辑:程序博客网 时间:2024/06/05 18:55

本文只做自己学习笔记记录,如有涉及他人版权,请联系我第一时间修改删除

背景介绍:

当用户触发了某个操作后,发送短信消息给另外的一个或者多个人;如果用户量比较少,同时发送消息的人也比较少时,直接在触发操作完成时发送消息即可,但是如果同时发送消息的人非常多咋办?到时系统可能会一直卡在“消息正在发送中......” 这种状态,用户体验太差了。想到可以使用异步的方式,当用户触发操作完成后,把发送消息的任务放到后台执行。


放到后台执行,想到了两种解决方式:

1. Linux 下的 cron

每个触发发送消息的动作,统一将相关信息(接受人,消息内容等信息)保存到文件、内存或者数据库等其它可以持久化数据的地方,然后在服务器做一个定时任务,间隔读取文件、缓存(Redis, Memcahce)或者数据库中的信息,最后发送。但是服务器(Linux 服务器)的定时任务一般是每分钟执行一次;当然有解决方法,可以实现秒级发送,但是感觉不太好微笑。弃用该方式。


2. 使用Swoole,不做过多解释,代码很简单:

Swoole客户端代码: SwooleClient.php

<?phpclass Swoole_SwooleClient{private $client;public function __construct() {$this->client = new swoole_client(SWOOLE_SOCK_TCP);}public function connect() {if (!$this->client->connect('127.0.0.1', 9502, 1)) {throw new Exception(sprintf('Swoole Error: %s', $this->client->errCode));}}public function send($data){if ($this->client->isConnected()) {if (!is_string($data)) {$data = json_encode($data);}return $this->client->send($data);} else {throw new Exception('Swoole Server does not connected.');}}public function close(){$this->client->close();}}



Swoole 服务代码:SwooleServer.php

<?php/** * Swoole服务器 */class Swoole_SwooleServer{private $logger = null;private $server = null;private $smtpConfig;private static $app;private $options = array();public function __construct($options = ''){$this->options = $options ?: array();$this->server = new swoole_server('127.0.0.1', 9502);$this->server->set(['worker_num' => 4,'daemonize' => false,'max_request' => 10000,'dispatch_mode' => 2,'debug_mode'=> 1,]);$this->server->on('Start', [$this, 'onStart']);$this->server->on('Connect', [$this, 'onConnect']);$this->server->on('Receive', [$this, 'onReceive']);$this->server->on('Close', [$this, 'onClose']);$this->server->start();}public function onStart(){}public function onConnect($server, $descriptors, $fromId){}public function onReceive(swoole_server $server, $descriptors, $fromId, $data){$sent = $this->send($data);// Swoole Server 接受到任务后调用发送动作,这是Yaf 框架下的使用方式,其它框架需要修改//printf("%s mail is sent.\n", $sent);}public function onClose($server, $descriptors, $fromId){}public function send($data){if (empty(self::$app)) {define("GUARD", 1);if (!defined("APP_PATH")) {define("APP_PATH", realpath(dirname(__FILE__) . '/../../../'));}define("APP", "yafapp");self::$app = new Yaf_Application(APP_PATH . "/conf/application.ini");}$config = Common::getConfig(APP);date_default_timezone_set($config->timezone);$con = $this->options['c'];$act = $this->options['a'];$params = json_decode($data, true);$request = new Yaf_Request_Simple("CLI", APP, $con, $act, $params);// Yaf 命令行unset($params);self::$app->getDispatcher()->dispatch($request);Yaf_Dispatcher::getInstance()->autoRender(false);}}if ($argc < 3) {echo "php a.php -c controller -a action\n" . "-c controller 控制器" ."-a action 动作";exit(-1);}set_time_limit(0); // 设置超时时间为0$opts = 'c:a:';$options = getopt($opts);$server = new Swoole_SwooleServer($options);


控制器调用SwooleClient:

$data = compact('content', 'mobiles');$swooleClient = new Swoole_SwooleClient();$swooleClient->connect();$send = $swooleClient->send($data);

负责具体发送消息的函数:SendMsgController.php

为啥把具体发送动作独立出来呢?考虑多种发送方式邮件、微信模版消息等等微笑。当然也可以直接放到SwooleServer.php 里面喽

<?phpclass SendMsgController extends Yaf_Controller_Abstract{public function init(){Yaf_Dispatcher::getInstance()->disableView();}/** * 发送消息 */public function sendSMSMsgAction(){$sms = new Sms();$params = $this->getRequest()->getParams();$content = $params['content'];$mobiles = implode(',', $params['mobiles']);return $sms->send($mobiles, $content);}}


最后将SwooleServer 运行:/usr/local/php/bin/php SwooleServer.php -c queue -a sendsmsmsg     >/dev/null 2>&1


注:

1. 如果 /usr/local/php/bin/php SwooleServer.php -c queue -a sendsmsmsg     >/dev/null 2>&1 这样开启的进程挂掉了咋办?如何保证他在挂掉后自动重启,方式很多,推荐使用supervisor微笑





0 0
原创粉丝点击