Heim  >  Artikel  >  Backend-Entwicklung  >  Erfahren Sie, wie Sie mit mixphp einen asynchronen E-Mail-Versand mit mehreren Prozessen erstellen

Erfahren Sie, wie Sie mit mixphp einen asynchronen E-Mail-Versand mit mehreren Prozessen erstellen

藏色散人
藏色散人nach vorne
2020-08-20 13:25:112629Durchsuche
Hinweis: Dies ist ein Beispiel für MixPHP V1

Das Versenden von E-Mails ist eine sehr häufige Anforderung. Da das Versenden von E-Mails im Allgemeinen zeitaufwändig ist, verwenden wir im Allgemeinen die asynchrone Verarbeitung, um die Benutzererfahrung zu verbessern Nachrichtenwarteschlangen zu erreichen.

Aufgrund des Mangels an Multiprozess-Entwicklungsfunktionen verwendet das traditionelle MVC-Framework normalerweise dasselbe Skript, um mehrere Prozesse zu generieren. Mixphp kapselt TaskExecutor und ist für die Multiprozessentwicklung konzipiert. Leistungsanwendungen mit vollständigen Funktionen verfügbar.

RECORMENDE: "php Video Tutorial"

Die folgt den Entwicklungsprozess eines asynchronen E -Mail -Sende -Systems mit Wissenspunkten: Nachrichtenwarteschlangenimplementierung asynchron verwenden

    PHP verwendet Nachrichtenwarteschlangen, die normalerweise Middleware verwenden:
  • redis
  • rabbitmq
  • kafka

Dieses Mal wählen wir Redis, um den asynchronen E-Mail-Versand zu implementieren. Redis Es gibt eine Liste Geben Sie den Datentyp ein, der die Nachrichtenwarteschlange implementieren kann:

// 入列
$redis->lpush($key, $data);
// 出列
$data = $redis->rpop($key);
// 阻塞出列
$data = $redis->brpop($key, 10);

Architekturdesign
  • Dieses Beispiel verwendet das traditionelle MVC-Framework, um die E-Mail-Versandanforderungen zu erfüllen, und MixPHP-Multiprozess, um die Sendeaufgabe auszuführen .
  • Auswahl der E-Mail-Versandbibliothek

In der Vergangenheit haben wir normalerweise die vom Framework bereitgestellte E-Mail-Versandbibliothek oder heruntergeladene Bibliotheken verwendet, die von anderen Benutzern online geteilt wurden. Nach dem Erscheinen von Composer gibt es eine große Anzahl hochwertiger Bibliotheken Auf https://packagist.org/ müssen wir nur den besten auswählen. In diesem Fall entscheiden wir uns für Swiftmailer.

Da die Sendeaufgabe von MixPHP ausgeführt wird, wird Swiftmailer im MixPHP-Projekt installiert. Führen Sie den folgenden Befehl im Projektstammverzeichnis aus, um ihn zu installieren:

composer require swiftmailer/swiftmailer

Producer development

In der Anforderung des E-Mail-Versands Produzent ist die Partei, die Aufgaben liefert und sendet. Dieser Teil muss nicht unbedingt von mixphp, CI und YII entwickelt werden Aufgabeninformationen in die Nachrichtenwarteschlange auf der Benutzeroberfläche oder auf der Webseite übertragen.

Fügen Sie den folgenden Code zum Controller des herkömmlichen MVC-Frameworks hinzu:

Wenn Redis in einem Framework verwendet wird, wird normalerweise eine Klassenbibliothek zur Verwendung installiert. In diesem Beispiel wird zum besseren Verständnis nativer Code verwendet.

// 连接
$redis = new \Redis();
if (!$redis->connect('127.0.0.1', 6379)) {
    throw new \Exception('Redis Connect Failure');
}
$redis->auth('');
$redis->select(0);
// 投递任务
$data = [
    'to'      => ['***@qq.com' => 'A name'],
    'body'    => 'Here is the message itself',
    'subject' => 'The title content',
];
$redis->lpush('queue:email', serialize($data));
Normalerweise wird bei der asynchronen Entwicklung sofort nach Abschluss der Übermittlung eine Nachricht an den Benutzer gesendet. Natürlich wird die Aufgabe zu diesem Zeitpunkt noch nicht ausgeführt.

Verbraucherentwicklung

In diesem Beispiel verwenden wir das Multiprozess-Entwicklungstool TaskExecutor von MixPHP, um diese Anforderung zu erfüllen. Residente Prozesse werden normalerweise zur Handhabung des Warteschlangenverbrauchs verwendet, daher verwenden wir den Typ TYPE_DAEMON und den Modus MODE_PUSH von TaskExecutor.

Der MODE_PUSH-Modus von TaskExecutor verfügt über zwei Prozesse:

Linker Prozess: Verantwortlich dafür, Aufgabendaten aus der Nachrichtenwarteschlange zu entnehmen und in den mittleren Prozess einzufügen.

Mittlerer Prozess: Verantwortlich für die Durchführung von E-Mail-Versandaufgaben.

PushCommand.php-Code lautet wie folgt:

<?php

namespace apps\daemon\commands;

use mix\console\ExitCode;
use mix\facades\Input;
use mix\facades\Redis;
use mix\task\CenterProcess;
use mix\task\LeftProcess;
use mix\task\TaskExecutor;

/**
 * 推送模式范例
 * @author 刘健 <coder.liu@qq.com>
 */
class PushCommand extends BaseCommand
{

    // 配置信息
    const HOST = &#39;smtpdm.aliyun.com&#39;;
    const PORT = 465;
    const SECURITY = &#39;ssl&#39;;
    const USERNAME = &#39;****@email.***.com&#39;;
    const PASSWORD = &#39;****&#39;;

    // 初始化事件
    public function onInitialize()
    {
        parent::onInitialize(); // TODO: Change the autogenerated stub
        // 获取程序名称
        $this->programName = Input::getCommandName();
        // 设置pidfile
        $this->pidFile = "/var/run/{$this->programName}.pid";
    }

    /**
     * 获取服务
     * @return TaskExecutor
     */
    public function getTaskService()
    {
        return create_object(
            [
                // 类路径
                &#39;class&#39;         => &#39;mix\task\TaskExecutor&#39;,
                // 服务名称
                &#39;name&#39;          => "mix-daemon: {$this->programName}",
                // 执行类型
                &#39;type&#39;          => \mix\task\TaskExecutor::TYPE_DAEMON,
                // 执行模式
                &#39;mode&#39;          => \mix\task\TaskExecutor::MODE_PUSH,
                // 左进程数
                &#39;leftProcess&#39;   => 1,
                // 中进程数
                &#39;centerProcess&#39; => 5,
                // 任务超时时间 (秒)
                &#39;timeout&#39;       => 5,
            ]
        );
    }

    // 启动
    public function actionStart()
    {
        // 预处理
        if (!parent::actionStart()) {
            return ExitCode::UNSPECIFIED_ERROR;
        }
        // 启动服务
        $service = $this->getTaskService();
        $service->on(&#39;LeftStart&#39;, [$this, &#39;onLeftStart&#39;]);
        $service->on(&#39;CenterStart&#39;, [$this, &#39;onCenterStart&#39;]);
        $service->start();
        // 返回退出码
        return ExitCode::OK;
    }

    // 左进程启动事件回调函数
    public function onLeftStart(LeftProcess $worker)
    {
        try {
            // 模型内使用长连接版本的数据库组件,这样组件会自动帮你维护连接不断线
            $queueModel = Redis::getInstance();
            // 保持任务执行状态,循环结束后当前进程会退出,主进程会重启一个新进程继续执行任务,这样做是为了避免长时间执行内存溢出
            for ($j = 0; $j < 16000; $j++) {
                // 从消息队列中间件阻塞获取一条消息
                $data = $queueModel->brpop(&#39;queue:email&#39;, 10);
                if (empty($data)) {
                    continue;
                }
                list(, $data) = $data;
                // 将消息推送给中进程去处理,push有长度限制 (https://wiki.swoole.com/wiki/page/290.html)
                $worker->push($data, false);
            }
        } catch (\Exception $e) {
            // 休息一会,避免 CPU 出现 100%
            sleep(1);
            // 抛出错误
            throw $e;
        }
    }

    // 中进程启动事件回调函数
    public function onCenterStart(CenterProcess $worker)
    {
        // 保持任务执行状态,循环结束后当前进程会退出,主进程会重启一个新进程继续执行任务,这样做是为了避免长时间执行内存溢出
        for ($j = 0; $j < 16000; $j++) {
            // 从进程消息队列中抢占一条消息
            $data = $worker->pop();
            if (empty($data)) {
                continue;
            }
            // 处理消息
            try {
                // 处理消息,比如:发送短信、发送邮件、微信推送
                var_dump($data);
                $ret = self::sendEmail($data);
                var_dump($ret);
            } catch (\Exception $e) {
                // 回退数据到消息队列
                $worker->rollback($data);
                // 休息一会,避免 CPU 出现 100%
                sleep(1);
                // 抛出错误
                throw $e;
            }
        }
    }

    // 发送邮件
    public static function sendEmail($data)
    {
        // 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($data[&#39;subject&#39;]))
            ->setFrom([self::USERNAME => &#39;**网&#39;])
            ->setTo($data[&#39;to&#39;])
            ->setBody($data[&#39;body&#39;]);
        // Send the message
        $result = $mailer->send($message);
        return $result;
    }

}
  • Test

    1 Starten Sie das push-residente Programm in der Shell.
  • [root@localhost bin]# ./mix-daemon push start
    mix-daemon &#39;push&#39; start successed.
    1. Rufen Sie die Schnittstelle auf, um die Aufgabe in die Nachrichtenwarteschlange zu stellen.
  • Zu diesem Zeitpunkt druckt das Shell-Terminal:

Test-E-Mail erfolgreich erhalten:

Erfahren Sie, wie Sie mit mixphp einen asynchronen E-Mail-Versand mit mehreren Prozessen erstellenMixPHP

GitHub: https://github.com/mix-php /mix

Offizielle Website: http://www.mixphp.cn/

Erfahren Sie, wie Sie mit mixphp einen asynchronen E-Mail-Versand mit mehreren Prozessen erstellen

Das obige ist der detaillierte Inhalt vonErfahren Sie, wie Sie mit mixphp einen asynchronen E-Mail-Versand mit mehreren Prozessen erstellen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen