如何有选择的将事件监听器 (Event Listeners) 推送到队列中

本文翻译自Conditionally pushing event listeners to queue

情景模拟

假设有以下情况,你正在构建一个日成交量成千上万个订单的在线商城,一个很酷的功能是如果用户购买超过 1万元将会获得一个优惠券,让我们看看在Laravel中怎样实现。

代码实现

在每一笔订单支付成功的时候我们可以通过 Laravel 的 Event事件执行一系列的操作:

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        NewPurchase::class => [
            SendInvoice::class,
            UpdateMetrics::class,
            SendShippingOrder::class,
            SendGiftCoupon::class,
        ],
    ];
}

当每一个事件触发时,SendGiftCoupon 将会调用,代码如下:

class SendGiftCoupon
{
    public function handle($event)
    {
        $customer = $event->customer;

        if ($customer->purchases >= 10000 && ! $customer->wasGifted()) {
            $coupon = Coupon::createForCustomer($customer);

            Mail::to($customer)->send(new CouponGift($customer));
        }
    }
}

在这个 Listener 中我们会检查消费者能否获得优惠券,如果可以,那么发送优惠券到消费者的邮箱中。

优化处理

上面代码的问题是我们必须要等到所有步骤处理完毕之后才会生成订单。如果我们只同步处理订单,将发送邮件等动作稍后处理是一个更好的解决方案,在 Laravel 中 我们可以通过继承 ShouldQueue 很简单的实现:

class SendGiftCoupon implements ShouldQueue
{
    // 其余代码
}

直到这里,我们看似解决了问题。

问题浮现

那么究竟有多少顾客会达到 1 万元的消费呢?每次购买时将发送优惠券推送到队列是否合理(毕竟购买金额达到 1 万元的始终是少数,因此大部分的 Listener 将不会进行任何的操作)?这样你将会看到你的队列中有很多无用的 Job 在执行。

解决方案

一个解决方案是只在有必要的时候才进行队列处理,其余时候则可以完全忽略,幸运的是 Laravel 中我们可以非常容易的实现。我们仅需要做的就是在 Listener 类中加入 shouldQueue 方法即可:

public function shouldQueue($event)
{
    return $event->customer->purchases > 10000 &&
        ! $event->customer->wasGifted();
}

加入上面的代码后,Laravel 在推送队列前会进行检查,符合要求的才会进行处理,否则不会将其加入到队列中。

结论

与其让我们的队列处理无数的无效 Job,不如在必要的时候才推送到队列中。

本作品采用《CC 协议》,转载必须注明作者和本文链接
There's nothing wrong with having a little fun.
Epona
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!