在 Laravel 项目中,生产者消费者模式常用于处理批量导出、消息通知、状态同步等耗时任务。Eloquent Attribute TransferQueue 的核心思路,是把 Eloquent 模型的属性变化作为队列消息的生产入口:当模型字段满足预设条件时,组件会把指定属性封装成消息投递到队列,再由消费者任务统一处理。这样业务代码不需要在每个更新位置手动拼装消息,也能让生产者与消费者围绕同一份传输规则协作。

一、属性变化驱动队列消息的核心思路
传统做法是在控制器或服务中更新模型后,再手动 dispatch 一个 Job,并把需要传递的字段逐个传入。这种方式在字段少时可行,但一旦业务变复杂,容易出现消息字段遗漏、模型序列化过大、生产逻辑分散等问题。TransferQueue 的价值在于把“哪些属性需要传输”和“什么条件触发传输”收敛到模型内部,让数据变化本身成为生产事件。
从职责划分看,生产者并不一定是一个独立服务,而是模型属性更新过程中的条件判断与数据封装。消费者则是一个队列任务,只接收传输消息并执行业务。配置项负责指定消费者类、队列连接和重试次数。三者分离后,修改传输字段时主要调整模型,修改处理逻辑时主要调整任务,整体结构更清晰。
这种模式特别适合订单状态变化、审批结果变化、数据同步标记变化等场景。例如订单状态变为已支付时,需要发送通知或同步到下游系统;此时不必把整个订单对象交给队列,而只传递订单编号、金额、状态等必要字段,降低队列消息体积,也减少消费者对无关字段的依赖。
二、安装依赖、发布配置与基础运行环境
使用 TransferQueue 前,需要在 Laravel 项目中安装对应依赖。安装完成后,组件会提供模型可用的传输队列能力,以及可发布的配置文件。下面命令用于引入依赖。
composer require vendor/eloquent-attribute-transfer-queue
依赖安装后,需要发布配置文件,以便在项目内修改队列连接、消费者任务和重试策略。发布命令会读取组件的 Service Provider,并把默认配置复制到项目的 config 目录。
php artisan vendor:publish --provider="EloquentAttributeTransferQueueTransferQueueServiceProvider"
配置文件中最重要的三项分别是 consumer_job、queue_connection 和 retry_times。consumer_job 指定接收传输消息的队列任务类;queue_connection 指定队列驱动,例如 redis;retry_times 指定失败后的重试次数。对于基础场景,保持默认连接即可,但消费者任务必须指向实际处理业务的任务类。
<?php
return [
'consumer_job' => AppJobsProcessOrderTransfer::class,
'queue_connection' => 'redis',
'retry_times' => 3,
];
在运行测试前,需要先启动队列监听进程。队列监听进程会持续从指定连接中取出待处理任务,并调用消费者任务的 handle 方法。如果项目使用 redis 驱动,需要确保 redis 服务可用,并且环境变量中的队列连接配置正确。
php artisan queue:work
三、定义模型、传输属性与触发条件
以订单模型为例,Order 模型需要引入 HasTransferQueue 特性,并声明需要传输的属性与触发条件。transferAttributes 表示消费者最终能拿到的字段列表,transferConditions 表示满足哪些字段值时才触发传输。这样模型既保留了普通 Eloquent 行为,又具备了属性变化后的队列生产能力。
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
use EloquentAttributeTransferQueueTraitsHasTransferQueue;
class Order extends Model
{
use HasTransferQueue;
protected $table = 'orders';
protected $fillable = ['order_no', 'total_amount', 'status'];
protected $transferAttributes = ['id', 'order_no', 'total_amount', 'status'];
protected $transferConditions = [
'status' => 2,
];
}
transferAttributes 的设计重点是“最小必要字段”。如果只传 id、order_no、total_amount、status,消费者就能完成多数通知或同步逻辑,而不需要依赖完整订单数据。这样也能避免把敏感字段或大字段带入队列。若后续需要扩展字段,只需修改该数组或扩展 getTransferData 方法,而不必改动消费者入口结构。
transferConditions 是生产者判断的核心。示例中 status 等于 2 时触发传输,意味着只有订单状态更新为目标状态时,才会生成消息。若一次更新没有改变 status,或 status 更新为其他值,则不会触发。这样的条件约束可以减少无效任务,避免每次保存都向队列投递消息。
在业务服务中,生产者逻辑可以非常简洁。OrderService 的 updateOrderStatus 方法只负责查找订单并更新状态,真正的消息封装与投递由模型中的传输规则完成。调用方不需要感知队列细节,也不需要手动构造消息体。
<?php
namespace AppServices;
use AppModelsOrder;
class OrderService
{
public function updateOrderStatus(int $orderId, int $status): Order
{
$order = Order::findOrFail($orderId);
$order->update(['status' => $status]);
return $order;
}
}
四、实现消费者任务、运行验证与异常处理
消费者通常是一个队列 Job。通过 artisan 命令生成任务类后,在构造函数中接收 TransferQueueMessage,并在 handle 方法中读取消息数据。TransferQueueMessage 是生产者与消费者之间的契约,消费者通过它获取传输过来的属性集合。
php artisan make:job ProcessOrderTransfer
ProcessOrderTransfer 任务的核心是调用 getData 方法取得订单数据,然后执行通知、同步、日志等逻辑。示例中只记录日志,便于验证链路是否打通。如果业务处理失败,可以抛出异常,让队列按照配置进行重试。
<?php
namespace AppJobs;
use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;
use IlluminateQueueInteractsWithQueue;
use IlluminateQueueSerializesModels;
use EloquentAttributeTransferQueueContractsTransferQueueMessage;
use IlluminateSupportFacadesLog;
class ProcessOrderTransfer implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $message;
public function __construct(TransferQueueMessage $message)
{
$this->message = $message;
}
public function handle()
{
$orderData = $this->message->getData();
Log::info('收到订单传输数据', $orderData);
}
}
为了验证完整流程,可以添加一个测试路由。路由先创建一条状态为 1 的测试订单,再调用服务方法把状态更新为 2。当状态满足 transferConditions 后,消息会被投递到队列,队列监听进程随后取出并执行消费者任务。
<?php
use AppModelsOrder;
use AppServicesOrderService;
use IlluminateSupportFacadesRoute;
Route::get('/test-transfer', function () {
$service = new OrderService();
$order = Order::create([
'order_no' => 'TEST_' . time(),
'total_amount' => 100.00,
'status' => 1,
]);
$service->updateOrderStatus($order->id, 2);
return '触发传输成功,请查看队列日志';
});
访问测试路由后,可以在日志中看到消费者接收到的订单数据。如果消费者处理失败,队列会根据 retry_times 自动重试;超过次数后任务进入失败队列。通过 queue:failed 命令可以查看失败任务,通过 queue:retry 命令可以重新执行指定任务。
php artisan queue:failed php artisan queue:retry 任务ID
如果传输内容需要包含关联关系,可以在模型中自定义 getTransferData 方法。示例中在基础字段之外附加用户信息,只取用户 id 和 name,避免把完整用户模型带入队列。这种方式适合消费者需要少量关联上下文的场景,同时保持消息结构可控。
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
use EloquentAttributeTransferQueueTraitsHasTransferQueue;
class Order extends Model
{
use HasTransferQueue;
protected $table = 'orders';
protected $fillable = ['order_no', 'total_amount', 'status'];
protected $transferAttributes = ['id', 'order_no', 'total_amount', 'status'];
protected $transferConditions = [
'status' => 2,
];
public function getTransferData(): array
{
$baseData = $this->only($this->transferAttributes);
$baseData['user'] = $this->user ? $this->user->only(['id', 'name']) : null;
return $baseData;
}
public function user()
{
return $this->belongsTo(User::class);
}
}
总体来看,Eloquent Attribute TransferQueue 把生产者消费者模式中的生产动作与 Eloquent 属性变化绑定,使业务更新与异步处理之间形成稳定接口。实际使用时,应重点关注传输字段最小化、触发条件准确、消费者任务幂等、失败重试策略合理。只要这些边界清晰,该模式就能在 Laravel 项目中有效降低同步处理耗时,并提升任务处理的可靠性。
PHPLaravelEloquent_Attribute_TransferQueue生产者消费者模式修改时间:2026-07-13 02:18:34