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

Laravel 12 为所有队列任务应用全局中间件(类Web的withMiddleware)

Laravel 12 全局队列中间件实现方案(多租户场景)

核心思路

利用Laravel的总线(Bus)系统全局管道,为所有队列化任务(自定义任务、通知、队列事件、队列邮件等)自动注入多租户配置中间件,无需逐个修改任务类。

具体实现步骤

1. 注册全局总线管道中间件

在App\Providers\AppServiceProvider的boot方法中,添加全局中间件注册逻辑:

use Illuminate\Support\Facades\Bus;
use App\Http\Middleware\ConfigureJobTenantMiddleware; // 替换为你的中间件实际路径

public function boot()
{
    // 为所有总线任务(含队列任务)绑定全局中间件
    Bus::pipeThrough([
        ConfigureJobTenantMiddleware::class,
    ]);
}

2. 适配中间件处理逻辑

调整你的ConfigureJobTenantMiddleware,兼容不同类型队列任务的tenant_id提取与配置切换:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Queue\ShouldQueue;

class ConfigureJobTenantMiddleware
{
    public function handle($job, Closure $next)
    {
        if ($job instanceof ShouldQueue) {
            $tenantId = $this->extractTenantId($job);
            
            if ($tenantId) {
                // 保存原始配置,执行后恢复(避免污染后续任务)
                $originalMailConfig = config('mail.default');
                
                // 设置租户专属配置,示例:切换邮件驱动、应用URL等
                config(['mail.default' => "tenant_{$tenantId}_mail"]);
                config(['app.url' => "https://tenant{$tenantId}.yourdomain.com"]);
            }
        }

        // 执行任务
        $result = $next($job);

        // 恢复原始配置
        if (isset($originalMailConfig)) {
            config(['mail.default' => $originalMailConfig]);
        }

        return $result;
    }

    /**
     * 从不同类型队列任务中提取tenant_id
     */
    private function extractTenantId($job)
    {
        // 处理自定义任务:任务自身携带tenantId属性
        if (property_exists($job, 'tenantId')) {
            return $job->tenantId;
        }

        // 处理队列通知:从通知的Notifiable实例中获取
        if (method_exists($job, 'getNotifiable')) {
            $notifiable = $job->getNotifiable();
            return $notifiable->tenant_id ?? null;
        }

        // 处理队列邮件:从邮件实例关联的用户模型中获取
        if (method_exists($job, 'mailable') && $job->mailable) {
            $mailable = $job->mailable;
            return $mailable->user?->tenant_id ?? null;
        }

        // 处理队列事件:从事件实例中获取
        if (method_exists($job, 'event') && $job->event) {
            $event = $job->event;
            return $event->tenantId ?? $event->model?->tenant_id ?? null;
        }

        return null;
    }
}

3. 验证生效范围

该方案会自动覆盖所有Laravel总线分发的队列任务:

  • 自定义队列任务(实现ShouldQueue接口)
  • 队列化通知(Notification::queue()/sendLater())
  • 队列化邮件(Mail::queue()/sendLater())
  • 队列化事件(Event::dispatchAfterResponse()/queue())

关键注意事项

  • 配置隔离:队列任务异步执行,必须在任务结束后恢复原始配置,防止影响后续任务的运行环境。
  • 序列化兼容性:任务中传递的模型建议只携带ID,在中间件中重新查询完整模型,避免序列化/反序列化丢失数据。
  • 异常防护:添加try-catch逻辑处理tenant_id缺失的情况,避免任务因配置失败而中断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 14:12:40