Are you also stuck in redis, knowing why it is, and how to use it? A simple example of using message queues to send messages asynchronously under yii
Preparations for redis~~
First of all, you have to configure redis service. I have written some articles about redis service before. You can refer to them here. https://segmentfault.com/a/11...
yii's redis library: https://github.com/yiisoft/yi...
Using composer to install redis dependency Libraries
php composer.phar require --prefer-dist yiisoft/yii2-redis
Relevant configuration of web.php:
return [ //.... 'components' => [ 'redis' => [ 'class' => 'yii\redis\Connection', 'hostname' => 'localhost', 'port' => 6379, 'database' => 0, ], ] ];
At this point, redis can be used to operate in yii
redis ~ ~ synchronization and asynchronization
So how to achieve asynchronous message queue to send mail?
The traditional method of operation is as follows:
User Input Mail Information
The server obtains the data input by the user and submits it to the third party's mail server.
Third Party Mail Server Sends Mail and Returns Processing Result
Asynchronous processing mail sending:
Users enter mail-related information
Store registration information in memory queue to inform the user of successful sending
The server monitors the memory queue and sends the mail data in the memory queue in turn which is not perceived by the user.
What's the difference between the two?
Asynchronism is better than synchronization because the page is non-blocking and reduces the user's waiting time experience.
redis ~ ~ mail delivery
Principle:
Users input mail information, servers receive the incoming mail information and call the mail process, which is actually the process of assigning mail class attributes. At this time, we can grab the user's information, store it in the queue, and then read the mail information in turn, and send it.
//Instantiate mail components $mailer = Yii::$app->mailer->compose(); $mailer->setFrom('sender address'); $mailer->setTo('Addressee address'); $mailer->setSubject('Send title'); //if ($mailer->send() && $this->reg($data, 'regbymail')) { //Note that this itself is a direct call to the send method for sending and now override the parent method for processing with redis if ($mailer->queue()) { return true; }
At this time, we will instantiate the mail class to send mail. At this time, we can grab the mail information and store it in the queue.
<?php namespace mail\mailerqueue; use Yii; class Message extends \yii\swiftmailer\Message { /*Grab mail messages to redis queue*/ public function queue() { $redis = Yii::$app->redis; if (empty($redis)) { throw new \yii\base\InvalidConfigException('redis not found in config.'); } // 0 - 15 select 0 select 1 // db => 1 $mailer = Yii::$app->mailer; //Does the database stored in mail exist? if (empty($mailer) || !$redis->select($mailer->db)) { throw new \yii\base\InvalidConfigException('db not defined.'); } //Grabbing Mail Information $message = []; $message['from'] =array_keys($this->from); $message['to'] = array_keys($this->getTo()); $message['cc'] = array_keys($this->getCc()); $message['bcc'] = array_keys($this->getBcc()); $message['reply_to'] = array_keys($this->getReplyTo()); $message['charset'] = array_keys($this->getCharset()); $message['subject'] = array_keys($this->getSubject()); //Get mail information and sub-information $parts = $this->getSwiftMessage()->getChildren(); if (!is_array($parts) || !sizeof($parts)) { $parts = [$this->getSwiftMessage()]; } foreach ($parts as $part) { if (!$part instanceof \Swift_Mime_Attachment) { //Get the content type switch($part->getContentType()) { case 'text/html': $message['html_body'] = $part->getBody(); break; case 'text/plain': $message['text_body'] = $part->getBody(); break; } if (!$message['charset']) { $message['charset'] = $part->getCharset(); } } } //The serialized fetched content is stored in the queue return $redis->rpush($mailer->key, json_encode($message)); } } //The next step is to read the redis queue and send it. <?php namespace mail\mailerqueue; use Yii; class MailerQueue extends \yii\swiftmailer\Mailer { public $messageClass = "doctorjason\mailerqueue\Message"; public $key = 'mails'; public $db = '1'; /*Send mail*/ public function process() { $redis = Yii::$app->redis; if (empty($redis)) { throw new \yii\base\InvalidConfigException('redis not found in config.'); } //If there is data in the queue if ($redis->select($this->db) && $messages = $redis->lrange($this->key, 0, -1)) { $messageObj = new Message; //Traveling through mailing lists foreach ($messages as $message) { $message = json_decode($message, true); if (empty($message) || !$this->setMessage($messageObj, $message)) { throw new \ServerErrorHttpException('message error'); } if ($messageObj->send()){ $redis->lrem($this->key, -1, json_encode($message)); } } } return true; } //Setting up message headers public function setMessage($messageObj, $message) { if (empty($messageObj)) { return false; } if (!empty($message['from']) && !empty($message['to'])) { $messageObj->setFrom($message['from'])->setTo($message['to']); if (!empty($message['cc'])) { $messageObj->setCc($message['cc']); } if (!empty($message['bcc'])) { $messageObj->setBcc($message['bcc']); } if (!empty($message['reply_to'])) { $messageObj->setReplyTo($message['reply_to']); } if (!empty($message['charset'])) { $messageObj->setCharset($message['charset']); } if (!empty($message['subject'])) { $messageObj->setSubject($message['subject']); } if (!empty($message['html_body'])) { $messageObj->setHtmlBody($message['html_body']); } if (!empty($message['text_body'])) { $messageObj->setTextBody($message['text_body']); } return $messageObj; } return false; } }
So far we have implemented redis queue to send mail asynchronously