I created a Laravel Job with 3 tries and timeout after 10 minutes. I am using Horizon.
I can handle the failure after 3 tries using the method failed
, but how can I handle the timeout event each 3 tries of this job ?
Used for logging and feedback, I want my user to be notified when the first or second try fails and it will be retried later.
class MyJob implements ShouldQueue
{
public $tries = 3;
public $timeout = 600;
// [...]
public function failed(Throwable $exception)
{
// The failure of the 3 tries.
}
// Any method for catching each timeouts ?
}
3
Answers
Ok I found the solution.
TLDR;
Put a
pcntl_signal
at the beginning of your your jobhandle()
and then you can do something like call aonTimeout()
method :The story behind :
The Queue documentation says :
The pcntl PHP extension must be installed in order to specify job timeouts.
So, digging into the pcntl PHP documentation I found interesting
pcntl_*
functions. And a call ofpcntl_signal
into Illuminate/Queue/Worker.php l221.It looks that if we register a method using
pcntl_signal
it replace the previous handler. I tried to load the Laravel one usingpcntl_signal_get_handler
but I can't manage to call it. So the workaroud is to callexit;
so Laravel will consider the process as lost and mark it as timeout (?). There is the 3 tries, the retry_after is respected, and at the last try the job fails ... It may be cleaner to keep the original handler, but as it work well on my case so I will stop investigate.https://laravel.com/docs/9.x/queues#failing-on-timeout
I dont think there is a method for that,
But you can do something like catch the Error thrown if the job fails and verify that its from timeout exception which I believe would throw the exception handler
SymfonyComponentProcessExceptionProcessTimedOutException
.Something like;
Just try running a job and make sure it fails because of timeout, to verify the actual timeout class exception