Swoole实验室:3-使用Swoole批量发送邮件

栏目: PHP · 发布时间: 6年前

内容简介:在上一节中我们介绍了使用Swoole发送单个邮件,那么如果是大量的邮件需要发送,比如给2万个用户发送优惠活动邮件,这是一个比较耗时的过程,而PHP本身不适合处理这种耗时多任务场景。本节为给大家介绍使用Swoole+Redis来实现发送批量邮件的例子。

在上一节中我们介绍了使用Swoole发送单个邮件,那么如果是大量的邮件需要发送,比如给2万个用户发送优惠活动邮件,这是一个比较耗时的过程,而 PHP 本身不适合处理这种耗时多任务场景。本节为给大家介绍使用Swoole+Redis来实现发送批量邮件的例子。

建立任务

接上一节代码,编辑src/App/Mail.php文件代码,在 public function onTask() 方法中增加批量队列发送邮件的代码:

public function onTask(swoole_server $serv, $task_id, $from_id, $data)
    {
        $res['result'] = 'failed';
        $req = json_decode($data, true);
        $action = $req['action'];
        echo date('Y-m-d H:i:s')." onTask: [".$action."].\n";
        switch ($action) {
            case 'sendMail': //发送单个邮件
                $mailData = [
                    'emailAddress' => 'abc@example.com', //接收方,改成自己的邮箱可以测试接收邮件
                    'subject' => 'swoole实验室',
                    'body' => '测试This is the HTML message body.',
                    'attach' => '/home/swoole/public/a.jpg'
                ];
                $this->sendMail($mailData);
                break;

            case 'sendMailQueue': // 批量队列发送邮件
                $this->sendMailQueue();
                break;
            
            default:
                break;
        }
    }

建立 Redis 队列

由于发送的邮件比较多,我们把邮件列表事先保存在Redis队列中。我们知道Redis的使用场景很多,其中就可以用它来做简单的队列。

我们在任务中调用了 sendMailQueue() 方法,继续在Mail.php中添加:

// 邮件发送队列
    private function sendMailQueue()
    {
        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379);
       
        $password = '123';
        $redis->auth($password);

        swoole_timer_tick(1000, function($timer) use ($redis) { // 启用定时器,每1秒执行一次
            $value = $redis->lpop('mailerlist');
            if($value){
                //echo '获取redis数据:' . $value;
                $json = json_decode($value, true);
                $start = microtime(true);
                $rs = $this->sendMail($json);
                $end = microtime(true);
                if ($rs) {
                    echo '发送成功!'.$value.', 耗时:'. round($end - $start, 3).'秒'.PHP_EOL;
                } else { // 把发送失败的加入到失败队列中,人工处理
                    $redis->rpush("mailerlist_err", $value);
                }
            }else{
                swoole_timer_clear($timer); // 停止定时器
                echo "Emaillist出队完成";
            }
        });
    }

上述代码中,先尝试连接Redis,然后使用Swoole的 swoole_timer_tick() 函数,它是个定时器,这个函数跟js的interval()函数一样,意思是每隔一定时间执行一次,它可以定义毫秒级粒度。很显然,上述代码中,每隔1000毫秒(1秒)从Redis队列mailerlist中取出一条,即一个邮件对象,然后执行发送邮件 sendMail() ,当发送完所有邮件后,使用 swoole_timer_clear() 关闭定时器即可。定时器的间隔时间可以调整。

客户端

在客户端,我们先往Redis队列里添加邮件内容,然后向服务端发起 sendMailQueue 批量发邮件指令。

<?php 
class Client
{
    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) ) {
            echo "Error: {$this->client->errMsg}[{$this->client->errCode}]\n";
        }
        
        $action = 'sendMailQueue';
        $time = time();
        $key = 'MYgGnQE33ytd2jDFADS39DSEWsdD24sK';
        $token = md5($action.$time.$key);
        $data = [
            'action' => $action,
            'token' => $token,
            'timestamp' => $time
        ];
        $msg = json_encode($data);

        $this->client->send( $msg );
        $message = $this->client->recv();
        echo "Get Message From Server:{$message}\n";
    }
}


$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$password = '123';
$redis->auth($password);

$arr = [];

$arr[0] = [
    'subject' => '国庆大酬宾,全场1折',
    'emailAddress' => 'axxxx@example.com',
    'body' => '您好,国庆期间大酬宾,全场所有商品统统1折甩卖。'
];
$arr[1] = [
    'subject' => '注册会员送100金币',
    'emailAddress' => 'bxxxx@example.com',
    'body' => '邮件内容'
];
$arr[2] = [
    'subject' => '国庆大酬宾,全场1折',
    'emailAddress' => 'cxxxxx@example.com',
    'body' => '邮件内容2'
];
      
foreach ($arr as $k=>$v) {
    $redis->rpush("mailerlist", json_encode($v, JSON_UNESCAPED_UNICODE));
}


$client = new Client();
$client->connect();

验证

根据上一节内容,我们应该先启动服务端,看到Swoole服务端启动好了,我们再运行客户端:

php mailClient.php

然后你可以去查看对方邮箱是否收到相关邮件。

本文中使用了redis作为简单队列,你也可以使用复杂点的队列rabbitmq。你也可以使用Crontab来做定时任务,不过它最小粒度是分钟级别的。当然对于批量发送邮件,如果你不用php的话,可以用 Python 或者Java,它们都有相当成熟的解决方案。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Beginning XSLT 2.0

Beginning XSLT 2.0

Jeni Tennison / Apress / 2005-07-22 / USD 49.99

This is an updated revision of Tennison's "Beginning XSLT", updated for the new revision of the XSLT standard. XSLT is a technology used to transform an XML document with one structure into another ......一起来看看 《Beginning XSLT 2.0》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具