异步发送邮件完整示例
本章使用task异步进程进行邮件发送,来阐述一下以上章节提到的各个知识点。
邮件类
下载swiftmailer
composer require "swiftmailer/swiftmailer:^6.0"
Mailer.php 与 vender目录 同级
require_once __DIR__ . '/vendor/autoload.php';
class Mailer
{
public $transport;
public $mailer;
/**
* 发送邮件类 参数 $data 需要三个必填项 包括 邮件主题`$data['subject']`、接收邮件的人`$data['to']`和邮件内容 `$data['content']`
* @param Array $data
* @return bool $result 发送成功 or 失败
*/
public function send($data)
{
$this->transport = (new Swift_SmtpTransport('smtp.qq.com', 25))
->setEncryption('tls')
->setUsername('bailangzhan@qq.com')
->setPassword('xxxxxx');
$this->mailer = new Swift_Mailer($this->transport);
$message = (new Swift_Message($data['subject']))
->setFrom(array('bailangzhan@qq.com' => '白狼栈'))
->setTo(array($data['to']))
->setBody($data['content']);
$result = $this->mailer->send($message);
// 释放
$this->destroy();
return $result;
}
public function destroy()
{
$this->transport = null;
$this->mailer = null;
}
}
Server
后端启动:php server.php
这里单独拆分了一个TaskRun类,并且在onWorkerStart之后进行载入,主要是为了之后的“平滑重启“
class TaskServer
{
private $_serv;
private $_run;
public function __construct()
{
$this->_serv = new Swoole\Server("127.0.0.1", 9501);
$this->_serv->set([
'worker_num' => 2,
'daemonize' => false, //是否开启守护进程
'log_file' => __DIR__ . '/server.log', //守护进程调试日志
'task_worker_num' => 2,
'max_request' => 5000, //防止内存泄漏
'task_max_request' => 5000, //防止内存泄漏
'package_eof' => "\r\n", //设置EOF
'open_eof_split' => true, // 自动分包
]);
$this->_serv->on('Connect', [$this, 'onConnect']);
$this->_serv->on('Receive', [$this, 'onReceive']);
$this->_serv->on('WorkerStart', [$this, 'onWorkerStart']);
$this->_serv->on('Task', [$this, 'onTask']);
$this->_serv->on('Finish', [$this, 'onFinish']);
$this->_serv->on('Close', [$this, 'onClose']);
}
public function onConnect($serv, $fd, $fromId)
{
}
public function onWorkerStart($serv, $workerId)
{
require_once __DIR__ . "/TaskRun.php";
$this->_run = new TaskRun;
}
public function onReceive($serv, $fd, $fromId, $data)
{
$data = $this->unpack($data);
$this->_run->receive($serv, $fd, $fromId, $data);
// 投递一个任务到task进程中
if (!empty($data['event'])) {
$serv->task(array_merge($data , ['fd' => $fd]));
}
}
public function onTask($serv, $taskId, $fromId, $data)
{
$this->_run->task($serv, $taskId, $fromId, $data);
}
public function onFinish($serv, $taskId, $data)
{
$this->_run->finish($serv, $taskId, $data);
}
public function onClose($serv, $fd, $fromId)
{
}
/**
* 对数据包单独处理,数据包经过`json_decode`处理之后,只能是数组
* @param $data
* @return bool|mixed
*/
public function unpack($data)
{
$data = str_replace("\r\n", '', $data);
if (!$data) {
return false;
}
$data = json_decode($data, true);
if (!$data || !is_array($data)) {
return false;
}
return $data;
}
public function start()
{
$this->_serv->start();
}
}
$reload = new TaskServer;
$reload->start();
TaskRun 业务类
当此处修改了代码后,可以进行平滑重启,因为他是在Server端的onWorkerStart之后加载的文件。
require_once ('./Mailer.php');
class TaskRun
{
public function receive($serv, $fd, $fromId, $data)
{
}
public function task($serv, $taskId, $fromId, $data)
{
try {
switch ($data['event']) {
case 'send-mail':
$mailer = new Mailer;
$result = $mailer->send($data);
break;
default:
break;
}
return $result;
} catch (\Exception $e) {
throw new \Exception('task exception :' . $e->getMessage());
}
}
public function finish($serv, $taskId, $data)
{
return true;
}
}
Client
client加了eof,为了防止粘包,通过网址访问该程序
$client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
$client->connect('127.0.0.1', 9501) || exit("connect failed. Error: {$client->errCode}\n");
$data = [
'event' => 'send-mail',
'to' => '5566***@qq.com',
'subject' => 'just a test',
'content' => 'This just a test.',
];
$client->send(togetherDataByEof($data)); //发送数据给服务端
$client->close(); //关闭连接
/**
* 数据末尾拼接EOF标记
* @param Array $data 要处理的数据
* @return String json_encode($data) . EOF
*/
function togetherDataByEof($data)
{
if (!is_array($data)) {
return false;
}
return json_encode($data) . "\r\n";
}
赞赏码
非学,无以致疑;非问,无以广识