关于新增的异步回调方法

Typecho

如果你关注 Typecho 的更新日志,会发现我今天增加了一个比较重要的新特性:异步回调
https://github.com/typecho/typecho/commit/f180e8452de92a99d189779a67b6caf1ce2b26cf

顾名思义,它允许你创建一个异步的方法,并接受回调。主要用于一些会长时间阻塞同步请求而又不必等待返回结果的操作

它的主要原理是:
将这些等待时间较长的操作,注册到另一个 URL 中,当需要执行它们的时候,主进程带上必要的参数请求这个URL。同时不必等待这个请求返回,立即断开这个连接。此时,在执行 URL 的那个进程上,调用 PHP 的 ignore_user_abort 函数,忽略请求端的主动断开,继续执行到所有代码结束。

举一个典型的使用场景:评论的邮件提醒功能。发邮件由于需要用 SOCKS 请求 SMTP 接口,从发起连接,完成认证到发送结束,往往需要很长时间。这个时候用户的评论发送请求就会一直阻塞在那里,体验会非常不好。如果用异步回调将邮件发送过程封装进去,用户在提交评论后就不必等待邮件发送结束了。

使用方法,首先在 active 的时候注册一个回调放到 Widget_Service 里去

public static function activate() {
    Typecho_Plugin::factory('Widget_Feedback')->finishComment = array('Mailer_Plugin', 'send');
    Typecho_Plugin::factory('Widget_Service')->sendMail = array('Mailer_Plugin', 'sendMail');
}

在上面的代码中,我们还注册了一个 send 方法到 Widget_FeedbackfinishComment 钩子点,用于将参数发送到异步的回调中,这个 send 函数的实现非常简单,它不包含任何实际的发送代码,只是用 Helper::requestService 把刚刚新增的那条评论 coid 发送到异步回调 sendMail 中。

public static function send($comment)
{
    Helper::requestService('sendMail', $comment->coid);
}

而另一个用于在异步回调中执行的函数就包含了完整的发送逻辑

public static function sendMail($commentId)
{
    $options = Helper::options();
    $pluginOptions = $options->plugin('Mailer');
    $comment = Helper::widgetById('comments', $commentId);

    if (empty($pluginOptions->host)) {
        return;
    }

    if (!$comment->have() || empty($comment->mail)) {
        return;
    }
        
    $mail = new PHPMailer(false);
    // ... 剩下的都是请求代码
}

另外,我们还新增了一个常量 __TYPECHO_SERVICE_URL__,用于提高回调的性能。因为这个回调本质是通过 HTTP 网络接口请求自己,默认会使用你的外网正式访问地址作为访问前缀,对于某些使用了反向代理的用户其实可以更快地响应。首先在 /etc/hosts 文件里把网站域名指向 127.0.0.1,这样在发起网络请求的时候就不必使用外部的 DNS 解析,而且网络请求也会走本地环路大大地节省时间,如果你在本地使用了一个反向代理,可以在 config.inc.php 中直接把 __TYPECHO_SERVICE_URL__ 设置成反向代理的访问地址,比如

define('__TYPECHO_SERVICE_URL__', 'http://127.0.0.1:8080');

这是我做的一个完整的例子,异步回调版的评论邮件插件 Mailer.zip
注意:这个插件只能在最新的开发版中使用。

已有 33 条评论
  1. 好奇的Alpha
    好奇的Alpha

    这个好,邮件提醒终于有一个个完美的插件了。

  2. 启用插件后 syntax error, unexpected '000644' (T_LNUMBER)

    ParseError: syntax error, unexpected '000644' (T_LNUMBER) in /home/locred/public_html/usr/plugins/mailer.php:4876
    Stack trace:

    0 /home/locred/public_html/var/Widget/Plugins/Edit.php(308): Widget_Plugins_Edit->activate('mailer')1 /home/locred/public_html/var/Widget/Do.php(82): Widget_Plugins_Edit->action()2 /home/locred/public_html/var/Typecho/Widget.php(221): Widget_Do->execute()3 /home/locred/public_html/var/Typecho/Router.php(135): Typecho_Widget::widget('Widget_Do', NULL, Array)4 /home/locred/public_html/index.php(23): Typecho_Router::dispatch()5 {main}
      1. 你的插件目录放错了吧,这些文件要放到 usr/plugins/Mailer 目录下,你是不是把里面的文件解压出来了

  3. 博主博主 最新开发版12.13

  4. 博主博主 最新开发版12.13点开发版启用后错误500怎么办 官方找不到11.15的开发版了 能分享个嘛.

      1. 我并没有重现这个错误,你在 config.inc.php 里加上一行
        define('__TYPECHO_DEBUG__', true);

        看看具体的报错信息

      2. 修改 插件名称 Typecho-Plugin-Mailer-master 改 Mailer

  5. 尚寂新
    尚寂新

    希望正式版能有这个功能

      1. 尚寂新
        尚寂新

        已升级te最新开发版,已实装此插件,效果拔群,虽说设置的时候有错误提示吧,但也不耽误用,正常发信。

  6. 为了这个等会就升级开发版

  7. 测试了下 评论后邮件不会发送是什么原因呢

      1. 你的邮件参数是正确的么

          1. 是正确的 保存的时候没有提示出错,而且用这个配置使用另外一个插件是正常的

              1. 我用的是正常的,你看看日志,有没有正常回调

                  1. 失败了,找不到日志,请问是不是需要修改代码才可以使用?

                  2. 搞定了 不能用自己的SMTP地址而要用smtp.mxhichina.com。。。而且保存会提示向服务器发送指令错误,但是实际已经可以用了

  8. 这个压缩包里面是啥啊,未知属性 不会用!

  9. 成公笔记
    成公笔记

    好功能,希望评论邮件提醒插件能够尽快移植到正式版中。其实插件不用多,几个必要且使用的就行,尤其是官方版插件安全放心踏实。

  10. (Mailer插件)在后台回复的内容好像没有邮件提醒。

  11. 我用的是QQ企业免费邮箱,SSL/465端口,也是提示向服务器发送指令错误,但是能用。

  12. 学习笔记Blog
    学习笔记Blog

    其实我是真没有看懂异步回调,我就是喜欢分享的这个邮件插件!用起来感觉超好!速度快又稳定,强烈建议博主持续更新和优化这个插件, Typecho 确实需要一个轻便好用的评论邮件提醒插件的!

  13. 康康
    康康

    升级为最新版的开发版,然后使用插件,却发现邮件没有发送,在Plugin.php中修改了下代码:

    file_put_contents(__DIR__ . '/mailer.txt', 'begin'.PHP_EOL, FILE_APPEND);
    Helper::requestService('sendMail', $comment->coid);
    file_put_contents(__DIR__ . '/mailer.txt', 'end'.PHP_EOL, FILE_APPEND);

    以及:

    public static function sendMail($commentId)
    {

    file_put_contents(__DIR__ . '/mailer.txt', 'sendMail'.PHP_EOL, FILE_APPEND);
    

    评论后,可以看到begin和end的记录,可没有sendMail的记录,请问下是什么原因呢?

  14. 邮件服务器连接失败

  15. 尚寂新
    尚寂新

    dalao有个问题想问一下 我大概17年9月份安得这个插件(确保一下这个插件后面有没有更新) 发现了一个问题 邮件评论的时候会把其他人的邮箱暴露出去(插件用了邮件群发,群发的那些人的邮箱收件人都能看见)。如果能修复一下就好了

  16. 吃书虫子
    吃书虫子

    不支持 sqlite 数据库,建议更新支持下。一个个人博客,很少去用mysql。

  17. Typecho 支持异步回调版的评论邮件插件 Mailer-VPS优惠网_便宜VPS-便宜美国VPS、日本VPS、香港VPS、国内VPS推荐,便宜域名,便宜主机推荐

    [...]好在在joyqi.com的【关于新增的异步回调方法】一文里,作者分享的支持异步回调版的评论邮件插件 Mailer 明月竟然可以使用,插件非常的简洁,性能表现很不错,所以明月就推荐给大家,有需要的可以使用体验一下。[...]

  18. ChuHai5
    ChuHai5

    又学习长知识了。