异步发送邮件完整示例

本章使用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";
}

posted @ 2020-03-10 08:00  码农编程进阶笔记  阅读(50)  评论(0编辑  收藏  举报
返回顶部 有事您Q我