You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将多条订单通知合并为单个通知实例?

解决方案:聚合批量订单通知

要解决批量下单时重复发送通知的问题,核心思路是延迟聚合通知:先缓存短时间内的订单数量,延迟一段时间后再发送一条合并后的通知,而不是每条订单都单独发送。以下是具体实现步骤:

1. 修改订单观察者(OrderObserver)

不再直接发送通知,而是将订单计数存入缓存,并仅调度一次延迟任务处理聚合通知:

class OrderObserver
{
    /**
     * Handle the Order "created" event.
     *
     * @param  \App\Models\Order  $order
     * @return void
     */
    public function created(Order $order)
    {
        $cacheKey = 'pending_courier_orders';
        
        // 递增缓存中的订单计数,初始为1,过期时间与延迟任务一致
        Cache::increment($cacheKey, 1);
        // 存储订单ID列表(可选,用于后续跳转查看订单)
        Cache::push("{$cacheKey}_ids", $order->id);

        // 避免重复调度任务,仅当未调度时触发
        if (!Cache::has("{$cacheKey}_task_scheduled")) {
            SendAggregatedOrderNotification::dispatch()->delay(now()->addMinutes(1));
            Cache::put("{$cacheKey}_task_scheduled", true, now()->addMinutes(1));
        }
    }
}

2. 创建聚合通知处理任务

新建SendAggregatedOrderNotification任务,负责读取缓存中的订单数据并发送合并通知:

<?php

namespace App\Jobs;

use App\Models\User;
use App\Notifications\OrderReceived;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Cache;

class SendAggregatedOrderNotification implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function handle()
    {
        $cacheKey = 'pending_courier_orders';
        $orderCount = Cache::get($cacheKey, 0);
        $orderIds = Cache::get("{$cacheKey}_ids", []);

        // 无待处理订单时直接返回
        if ($orderCount <= 0) {
            return;
        }

        // 给所有快递员发送聚合通知
        User::couriers()->each(function ($courier) use ($orderCount, $orderIds) {
            $courier->notify(new OrderReceived($orderCount, $orderIds));
        });

        // 清理缓存
        Cache::forget($cacheKey);
        Cache::forget("{$cacheKey}_ids");
        Cache::forget("{$cacheKey}_task_scheduled");
    }
}

3. 修改OrderReceived通知类

更新通知类以支持接收订单数量,动态生成合并后的通知内容:

class OrderReceived extends Notification
{
    use Queueable;

    /**
     * 待通知的订单数量
     * 
     * @var int
     */
    protected int $orderCount;

    /**
     * 订单ID列表
     * 
     * @var array
     */
    protected array $orderIds;

    /**
     * 通知标题
     * 
     * @var string
     */
    protected string $title;

    /**
     * 通知内容
     * 
     * @var string
     */
    protected string $subtitle;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct(int $orderCount, array $orderIds)
    {
        $this->orderCount = $orderCount;
        $this->orderIds = $orderIds;

        // 根据订单数量生成对应文案
        if ($orderCount === 1) {
            $this->title = 'Pesanan Diterima!';
            $this->subtitle = 'Ada pesanan baru nih! Yuk cek dimana~';
        } else {
            $this->title = "{$orderCount} Pesanan Diterima!";
            $this->subtitle = "Ada {$orderCount} pesanan baru nih! Yuk cek dimana~";
        }
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return [FcmChannel::class];
    }

    public function toFcm($notifiable)
    {
        return FcmMessage::create()
            ->setData([
                'order_count' => $this->orderCount,
                'order_ids' => $this->orderIds
            ])
            ->setNotification(
                \NotificationChannels\Fcm\Resources\Notification::create()
                    ->setTitle($this->title)
                    ->setBody($this->subtitle)
            )
            ->setAndroid(
                AndroidConfig::create()
                    ->setFcmOptions(AndroidFcmOptions::create()->setAnalyticsLabel('analytics'))
                    ->setNotification(AndroidNotification::create()->setColor('#0A0A0A'))
            )->setApns(
                ApnsConfig::create()
                    ->setFcmOptions(ApnsFcmOptions::create()->setAnalyticsLabel('analytics_ios'))
            );
    }

    public function toMail($notifiable)
    {
        return (new MailMessage)
            ->line("Anda menerima {$this->orderCount} pesanan baru.")
            ->action('Lihat Pesanan', url('/orders'))
            ->line('Terima kasih menggunakan aplikasi kami!');
    }

    public function toArray($notifiable)
    {
        return [
            'order_count' => $this->orderCount,
            'order_ids' => $this->orderIds
        ];
    }
}

关键说明

  • 缓存与延迟时间:示例中设置1分钟的延迟和缓存过期时间,可根据业务需求调整(如30秒、2分钟),平衡通知实时性和聚合效果。
  • 缓存驱动:确保使用支持递增、列表操作的缓存驱动(如Redis),默认文件缓存无法支持这些操作。
  • 任务去重:通过缓存标记避免重复调度任务,防止同一时间段内多次触发通知发送。

内容的提问来源于stack exchange,提问作者Yura

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:09:59