В прошлом году, когда был выпущен mix PSP V1, я написал экземпляр многопроцессорной отправки электронной почты: используйте mix hp для создания многопроцессорной асинхронной отправки электронной почты. В этом году был выпущен mix PHP V2. Благодаря всесторонней поддержке совместной работы мы можем использовать один процесс для достижения более высокой производительности ввода-вывода, которая ранее не могла быть достигнута несколькими процессами. Поэтому сегодня мы переписываем версию экземпляра отправки электронной почты для пула совместной работы.
Отправка электронной почты-очень распространенное требование. Поскольку операция отправки электронной почты, как правило, занимает много времени, мы обычно используем асинхронную обработку для улучшения пользовательского интерфейса, а для достижения асинхронности обычно используем очередь сообщений.
Ниже показан процесс разработки асинхронной системы отправки почты с использованием точек знаний:
- асинхронный
- Очередь сообщений
- Демон
- Пул совместных каналов
Как использовать очередь сообщений для реализации асинхронности
В PHP очередь сообщений обычно реализуется с помощью промежуточного программного обеспечения, которое включает:
- редис
- кролик
- кафка
На этот раз мы используем redis для реализации асинхронной отправки почты. В типе данных redis есть тип списка, который может реализовывать очередь сообщений. Используйте следующую команду:
// column $redis->lpush($key, $data); // out $data = $redis->rpop($key); //Blocking out $data = $redis->brpop($key, 10);
архитектурный дизайн
В этом примере традиционная платформа MVC обеспечивает требования к отправке почты (производители), а демоны, написанные mix PHP, выполняют задачи отправки (потребители).
Выбор модели библиотеки отправки почты
В прошлом мы использовали библиотеку отправки электронной почты, предоставляемую платформой, или загружали библиотеку, которой пользуются другие пользователи в Интернете. После появления composer появилось большое количество высококачественных библиотек на https://packagist.org/. Нам просто нужно выбрать лучшее. В этом случае выберите swiftmailer.
Поскольку задача отправки выполняется mix PHP, swiftmailer устанавливается в проекте mix PHP. Выполните следующую команду в корневом каталоге проекта для установки:
composer require swiftmailer/swiftmailer
Развитие производителей
В требовании отправки электронной почты производитель ссылается на сторону, которая выполняет задачу отправки. Эта сторона обычно представляет собой интерфейс или веб-страницу. Эта часть не нуждается в разработке с помощью mix PHP. Доступны TP, CI и Yii. Только информация о задаче должна быть доставлена в очередь сообщений в интерфейсе или на веб-странице.
Добавьте следующий код в контроллер традиционной платформы MVC:
В общем случае при использовании redis в рамках будет установлена библиотека классов для использования. В этом случае для удобства понимания используется собственный код.
// connection $redis = new \Redis(); if (!$redis->connect('127.0.0.1', 6379)) { throw new \Exception('Redis connect failed.'); } $redis->auth(''); $redis->select(0); //Delivery task $data = [ 'to' => '***@qq.com', 'body' => 'The message content', 'subject' => 'The title content', ]; $redis->lpush('queue:email', serialize($data));
Обычно в асинхронной разработке сообщение будет отправлено пользователю сразу после доставки. Конечно, в настоящее время эта задача не выполняется в производителе, а только после того, как сообщение будет получено потребителем.
Развитие потребителей
При использовании этого примера убедитесь, что используемый вами swool скомпилирован с включенным OpenSSL
В этом примере мы используем демоны и пулы взаимодействия mix PHP V2 для выполнения сверхвысокой производительности программы отправки почты.
Поскольку мы разрабатываем демонов, мы приложения/демон
Прежде всего, мы настраиваем приложения/демон/конфигурация/главная.
php
Зарегистрируйте команду в:
// command 'commands' => [ 'mailer' => ['Mailer', 'description' => 'Mailer daemon.'], ],
Класс команды отправителя, указанный в зарегистрированной команде. Далее мы напишем класс команд почтовой рассылки:
applications/daemon/src/Commands/MailerCommand.php
[email protected]> */ class MailerCommand { /** * exit * @var bool */ public $quit = false; /** * main function */ public function main() { //Acquisition signal ProcessHelper::signal([SIGHUP, SIGINT, SIGTERM, SIGQUIT], function ($signal) { $this->quit = true; ProcessHelper::signal([SIGHUP, SIGINT, SIGTERM, SIGQUIT], null); }); //Pool execution task xgo(function () { $maxWorkers = 20; $maxQueue = 20; $jobQueue = new Channel($maxQueue); $dispatch = new Dispatcher([ 'jobQueue' => $jobQueue, 'maxWorkers' => $maxWorkers, ]); $dispatch->start(MailerWorker::class); //Launch task $redis = app()->redisPool->getConnection(); while (true) { if ($this->quit) { $dispatch->stop(); return; } try { $data = $redis->brPop(['queue:email'], 3); } catch (\Throwable $e) { $dispatch->stop(); return; } if (!$data) { continue; } $data = array_pop ($data); // the last key of brpop command is the value $jobQueue->push($data); } }); } }
из $data = $redis->brPop(['очередь:электронная почта'], 3);
Запись внешних исключений показывает, что при сбое подключения redis, например, при перезапуске redis или ненормальном подключении, пул совместной работы завершится безопасно, то есть, когда процесс завершится ненормально, пользователю необходимо использовать супервизор |/、 |/pm2
Дождаться инструментов для перезапуска демонов.
Выше приведен код использования пула совместной работы mix PHP, который можно скопировать напрямую. По умолчанию платформа содержит демонстрационную версию пула совместной работы. Этот экземпляр изменяет только работника пула совместной работы. Эта команда предназначена для получения сообщений из очереди redis и отправки их в очередь заданий. Данные в очереди заданий будут выполняться параллельно после того, как их вытеснит один из 20 рабочих экземпляров. Например, логика кода отправки почты относится к классу mailerworker:
applications/daemon/src/Libraries/MailerWorker.php
[email protected]> */ class MailerWorker extends AbstractWorker implements WorkerInterface { /** *Mail sender * @var Mailer */ public $mailer; /** *Initialize event */ public function onInitialize() { parent::onInitialize(); // TODO: Change the autogenerated stub //Instantiate some objects to be reused $this->mailer = new Mailer(); } /** * processing * @param $data */ public function handle($data) { // TODO: Implement handle() method. $data = unserialize($data); if (empty($data)) { return; } try { $this->mailer->send($data['to'], $data['subject'], $data['body']); app()->log->info("Mail sent successfully:to {to} subject {subject}", $data); } catch (\Throwable $e) { app()->log->error("Mail failed to send:to {to} subject {subject} error {error}", array_merge($data, ['error' => $e->getMessage()])); } } }
Из приведенного выше кода видно, что при инициализации рабочего добавляется новый атрибут класса mailer. Когда сообщение из очереди заданий будет доставлено, оно будет доставлено методу обработки. В этом методе экземпляр класса mailer используется для выполнения задачи отправки почты. Поэтому нам нужно написать почтовую программу для отправки:
applications/daemon/src/Libraries/Mailer.php
[email protected]> */ class Mailer { /** *Configuration information */ const HOST = 'smtpdm.aliyun.com'; const PORT = 465; const SECURITY = 'ssl'; const USERNAME = '***'; const PASSWORD = '***'; /** * Mailer constructor. */ public function __construct() { //Open the process hook Coroutine::enableHook(); } /** * send * @param $to * @param $subject * @param $body * @return int */ public function send($to, $subject, $body) { // Create the Transport $transport = (new \Swift_SmtpTransport(self::HOST, self::PORT, self::SECURITY)) ->setUsername(self::USERNAME) ->setPassword(self::PASSWORD); // Create the Mailer using your created Transport $mailer = new \Swift_Mailer($transport); // Create a message $message = (new \Swift_Message($subject)) ->Setfrom ([self:: username = > ->setTo($to) ->setBody($body); // Send the message return $mailer->send($message); } }
В отправителе почтового отправителя мы использовали библиотеку swiftmailer, установленную composer для отправки почты. Вся приведенная выше логика кода завершена. Теперь мы начинаем тестировать.
Сначала запустите демонов-потребителей:
[[email protected] bin]# ./mix-daemon mailer
Назовите сценарий производителя выше push.php
Затем выполните в cli (откройте новый терминал):
[[email protected] bin]# php /tmp/push.php
Результаты демонов потребителей:
[[email protected] bin]# ./mix-daemon mailer [info] 2019-04-15 11:48:36 [message] Mail sent successfully:to ***@qq.com subject The title content
Терминал командной строки печатает журнал успешной отправки, и отправка завершена.