排队的工作卡住了,表可能已锁定在Laravel中

时间:2019-02-21 14:31:28

标签: php mysql laravel queue

我正在使用队列在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();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您需要定义排队作业的最大尝试次数,否则将无限期尝试。使用database驱动程序时,这意味着尝试次数可能超过MySQL TINYINT UNSIGNED字段的最大值,从而导致在第256次尝试时引发数据库异常。

有两种方法可以做到这一点。

在启动工作进程时使用--tries

$ php artisan queue:work --tries=10

或在您的工作类别中定义$tries属性:

public $tries = 10;

两者同时存在时,$tries属性优先。

最好始终使用--tries与辅助进程一起指定最大尝试次数,以便排队的侦听器,邮件以及使用队列的其他任何操作最终都会因尝试过多而失败,并使用{{1 }}属性可在对特定作业有意义时覆盖该限制。

您的自定义错误消息未出现在日志中的原因是,$tries队列驱动程序在从队列中弹出作业时会更新databaseattempts字段,并且然后将作业发送到工人类。由于递增reserved_at会在工作程序运行之前引发未捕获的数据库异常,因此永远不会调用您的代码。