我有一份看起来像这样的工作:
<?php
namespace App\Jobs;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Redis;
class FakeJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/** @var User */
private $user;
public $tries = 30;
/**
* Create a new job instance.
*
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
try {
Redis::throttle('key')->allow(1)->every(60)->then(function () {
// Job logic...
throw new \Exception('fake exception');
$this->logInfo($this->user->name);
});
} catch(\Illuminate\Contracts\Redis\LimiterTimeoutException $e) {
$this->logInfo('inside LimiterTimeout catch, ' . $e->getMessage());
$this->release(1);
}
}
public function failed(\Exception $exception) {
// Send user notification of failure, etc...
$this->logInfo('inside failure, ' . $exception->getMessage());
}
public function logInfo($message) {
$path = storage_path('logs/FakeJob.log');
$logText = time() . ' ' . $message;
file_put_contents($path, $logText.PHP_EOL , FILE_APPEND | LOCK_EX);
}
}
现在您会注意到我在handle函数中有一个Redis调节器,并且我立即在回调中抛出了一个错误。这就是我正在测试的东西,那个错误就是出问题了。
[您知道,我试图区分LimiterTimeoutExceptions和Throttler回调内部引发的异常。当我通过sync
连接运行作业时,一切都会按预期进行:FakeJob::dispatch($user)->onConnection('sync');
由于我在上一个请求之后的60秒内发出了一个请求,因此发生了错误,该错误进入了LimiterTimeoutException
catch块,并且节气门回调转到failed
函数。
但是当我通过默认的调度程序(数据库)调度作业时,似乎每个错误都通过LimiterTimeoutException
catch块,直到达到重试限制为止-该错误进入了failed
函数,但不是“假异常”错误。
我对此感到非常困惑。
注意:即使我的'假异常'最终被LimiterTimeoutException
catch块捕获,但$e->getMessage()
函数由于某种原因也不会在那里返回fake exception
。但我100%确信是导致该错误的原因,因为这绝对不是由于这些测试中的调节器引起的。
[好,所以实际上发生的事情是,直到达到重试限制,无论发生什么异常,它都不会在failed()
函数中结束。如果我想以不同于其他所有错误的方式处理LimiterTimeoutException错误,则必须将我的Redis::throttle
调用包装在try-catch中,然后仅检查catch中的错误类型。