最近突然发现一个 Laravel 项目的队列任务没有正常执行,检查发现 laravel.log 日志文件居然短短时间居然有 2G 多,打开后看到错误信息主要如下:

[2024-06-03 10:00:02] production.ERROR: SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'attempts' at row 1 (SQL: update `queue` set `reserved_at` = 1529143202, `attempts` = 256 where `id` = 569) {"exception":"[object] (Illuminate\Database\QueryException(code: 22003): SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'attempts' at row 1 (SQL: update `queue` set `reserved_at` = 1529143202, `attempts` = 256 where `id` = 569) at /home/username/directory/vendor/laravel/framework/src/Illuminate/Database/Connection.php:664, PDOException(code: 22003): SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'attempts' at row 1 at /home/username/directory/vendor/laravel/framework/src/Illuminate/Database/Connection.php:483)
[stacktrace]
#0 /home/username/directory/vendor/laravel/framework/src/Illuminate/Database/Connection.php(624): Illuminate\Database\Connection->runQueryCallback('update `queue` ...', Array, Object(Closure))
#1 /home/username/directory/vendor/laravel/framework/src/Illuminate/Database/Connection.php(490): Illuminate\Database\Connection->run('update `queue` ...', Array, Object(Closure))
#2 /home/username/directory/vendor/laravel/framework/src/Illuminate/Database/Connection.php(423): Illuminate\Database\Connection->affectingStatement('update `queue` ...', Array)
#3 /home/username/directory/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2173): Illuminate\Database\Connection->update('update `queue` ...', Array)
#4 /home/username/directory/vendor/laravel/framework/src/Illuminate/Queue/DatabaseQueue.php(287): Illuminate\Database\Query\Builder->update(Array)
#5 /home/username/directory/vendor/laravel/framework/src/Illuminate/Queue/DatabaseQueue.php(268): Illuminate\Queue\DatabaseQueue->markJobAsReserved(Object(Illuminate\Queue\Jobs\DatabaseJobRecord))
#6 /home/username/directory/vendor/laravel/framework/src/Illuminate/Queue/DatabaseQueue.php(198): Illuminate\Queue\DatabaseQueue->marshalJob('default', Object(Illuminate\Queue\Jobs\DatabaseJobRecord))
#7 /home/username/directory/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(244): Illuminate\Queue\DatabaseQueue->pop('default')
#8 /home/username/directory/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(220): Illuminate\Queue\Worker->getNextJob(Object(Illuminate\Queue\DatabaseQueue), 'default')
#9 /home/username/directory/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(101): Illuminate\Queue\Worker->runNextJob('database', 'default', Object(Illuminate\Queue\WorkerOptions))
#10 /home/username/directory/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(85): Illuminate\Queue\Console\WorkCommand->runWorker('database', 'default')
#11 [internal function]: Illuminate\Queue\Console\WorkCommand->handle()
#12 /home/username/directory/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(29): call_user_func_array(Array, Array)
#13 /home/username/directory/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(87): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#14 /home/username/directory/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(31): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#15 /home/username/directory/vendor/laravel/framework/src/Illuminate/Container/Container.php(549): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#16 /home/username/directory/vendor/laravel/framework/src/Illuminate/Console/Command.php(183): Illuminate\Container\Container->call(Array)
#17 /home/username/directory/vendor/symfony/console/Command/Command.php(252): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#18 /home/username/directory/vendor/laravel/framework/src/Illuminate/Console/Command.php(170): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#19 /home/username/directory/vendor/symfony/console/Application.php(946): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#20 /home/username/directory/vendor/symfony/console/Application.php(248): Symfony\Component\Console\Application->doRunCommand(Object(Illuminate\Queue\Console\WorkCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#21 /home/username/directory/vendor/symfony/console/Application.php(148): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#22 /home/username/directory/vendor/laravel/framework/src/Illuminate/Console/Application.php(88): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#23 /home/username/directory/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(121): Illuminate\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#24 /home/username/directory/artisan(37): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#25 {main}
"} 

错误的字面原因是 Laravel 队列数据表: jobs 的 attempts 字段是 tinyint 无符号类型,最大值为 255 ,而程序要插入的 attempts 值为 256,超出了字段允许的最大值范围。

根本原因是运行队列任务时,没有指定任务错误的最大重试次数。

最大尝试次数

如果你的一个队列任务遇到了错误,你可能不希望无限制的重试。因此 Laravel 提供了各种方法来指定一个任务可以尝试多少次或多长时间。

指定任务可尝试的最大次数的其中一个方法是,通过 Artisan 命令行上的 --tries 开关。这将适用于调度作业的所有任务,除非正在处理的任务指定了最大尝试次数。

https://learnku.com/docs/laravel/10.x/queues/14873#max-job-attempts-and-timeout

因此在运行队列命令时,加上--tries 参数即可,比如:

php artisan queue:work --tries=3