我正在使用队列在Laravel应用程序中发送电子邮件通知。我将数据库用作队列驱动程序,所以有一个jobs
数据库表,看起来像:
id | queue | payload | attempts | reserved_at
我现在队列中有一堆未发送的消息,但这是第一个引起所有麻烦的消息:它在255
列中有attempts
,当我尝试删除其中的行时phpMyAdmin没有任何反应-挂起约30秒,然后显示空白屏幕。
重新启动MySQL之后,它使我删除了该行,并正确发送了所有其他消息。
该行的内容(我在payload
字段中仔细查看)在表面上与所有其他行相同。
这是正在执行的作业:
public function handle()
{
try {
$this->order->sendOrderConfirmation();
} catch( Exception $e ){
Log::info('Unable to dispatch order confirmation email.', [
'order' => $this->order->id,
'message' => $e->getMessage(),
'code' => $e->getCode(),
'line' => $e->getLine(),
'file' => $e->getFile()
]);
$this->release();
}
}
上面的日志消息在日志中找不到,但是我在日志中发现的是:
SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'attempts' at row 1 (SQL: update `jobs` set `reserved_at` = 1550737859, `attempts` = 256 where `id` = 1638) in /home/truvisi3/public_html/secure/vendor/laravel/framework/src/Illuminate/Database/Connection.php:647
似乎正在尝试增加尝试次数计数器,但是该字段限制为255。好的,但是为什么这会破坏整个队列,而不仅是这个过程?而我该怎么做才能阻止这种情况的发生(除了手动更改“尝试”列的格式以接受大量数字之外)?
编辑:这是工作类别
class DispatchOrderConfirmationEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* @var Order
*/
protected $order;
public $tries = 10;
/**
* Create a new job instance.
*
* @param Order $order
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
try {
$this->order->sendOrderConfirmation();
} catch( Exception $e ){
$this->release();
}
}
}
答案 0 :(得分:1)
您需要定义排队作业的最大尝试次数,否则将无限期尝试。使用database
驱动程序时,这意味着尝试次数可能超过MySQL TINYINT UNSIGNED
字段的最大值,从而导致在第256次尝试时引发数据库异常。
有两种方法可以做到这一点。
在启动工作进程时使用--tries
:
$ php artisan queue:work --tries=10
或在您的工作类别中定义$tries
属性:
public $tries = 10;
两者同时存在时,$tries
属性优先。
最好始终使用--tries
与辅助进程一起指定最大尝试次数,以便排队的侦听器,邮件以及使用队列的其他任何操作最终都会因尝试过多而失败,并使用{{1 }}属性可在对特定作业有意义时覆盖该限制。
您的自定义错误消息未出现在日志中的原因是,$tries
队列驱动程序在从队列中弹出作业时会更新database
和attempts
字段,并且然后将作业发送到工人类。由于递增reserved_at
会在工作程序运行之前引发未捕获的数据库异常,因此永远不会调用您的代码。