diff --git a/src/Illuminate/Queue/Console/WorkCommand.php b/src/Illuminate/Queue/Console/WorkCommand.php index 2ee07ddcb420..552c8e97008e 100644 --- a/src/Illuminate/Queue/Console/WorkCommand.php +++ b/src/Illuminate/Queue/Console/WorkCommand.php @@ -8,6 +8,7 @@ use Illuminate\Queue\Events\JobFailed; use Illuminate\Queue\Events\JobProcessed; use Illuminate\Queue\Events\JobProcessing; +use Illuminate\Queue\Events\JobReleasedAfterException; use Illuminate\Queue\Worker; use Illuminate\Queue\WorkerOptions; use Illuminate\Support\Carbon; @@ -79,6 +80,13 @@ class WorkCommand extends Command */ protected $latestStartedAt; + /** + * Holds the status of the last processed job, if any. + * + * @var string|null + */ + protected $latestStatus; + /** * Create a new queue work command. * @@ -180,6 +188,10 @@ protected function listenForEvents() $this->writeOutput($event->job, 'success'); }); + $this->laravel['events']->listen(JobReleasedAfterException::class, function ($event) { + $this->writeOutput($event->job, 'released_after_exception'); + }); + $this->laravel['events']->listen(JobFailed::class, function ($event) { $this->writeOutput($event->job, 'failed'); @@ -198,17 +210,30 @@ protected function writeOutput(Job $job, $status) { if ($status == 'starting') { $this->latestStartedAt = microtime(true); + $this->latestStatus = $status; + $formattedStartedAt = Carbon::now()->format('Y-m-d H:i:s'); return $this->output->write(" {$formattedStartedAt} {$job->resolveName()}"); } + if ($this->latestStatus && $this->latestStatus != 'starting') { + $formattedStartedAt = Carbon::createFromTimestamp($this->latestStartedAt)->format('Y-m-d H:i:s'); + + $this->output->write(" {$formattedStartedAt} {$job->resolveName()}"); + } + $runTime = number_format((microtime(true) - $this->latestStartedAt) * 1000, 2).'ms'; $dots = max(terminal()->width() - mb_strlen($job->resolveName()) - mb_strlen($runTime) - 31, 0); $this->output->write(' '.str_repeat('.', $dots)); $this->output->write(" $runTime"); - $this->output->writeln($status == 'success' ? ' DONE' : ' FAIL'); + + $this->output->writeln(match ($this->latestStatus = $status) { + 'success' => ' DONE', + 'released_after_exception' => ' FAIL', + default => ' FAIL', + }); } /** diff --git a/src/Illuminate/Queue/Events/JobReleasedAfterException.php b/src/Illuminate/Queue/Events/JobReleasedAfterException.php new file mode 100644 index 000000000000..4600c0b14bd3 --- /dev/null +++ b/src/Illuminate/Queue/Events/JobReleasedAfterException.php @@ -0,0 +1,33 @@ +job = $job; + $this->connectionName = $connectionName; + } +} diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 6fdf145391ef..f11e90e64fca 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -10,6 +10,7 @@ use Illuminate\Queue\Events\JobExceptionOccurred; use Illuminate\Queue\Events\JobProcessed; use Illuminate\Queue\Events\JobProcessing; +use Illuminate\Queue\Events\JobReleasedAfterException; use Illuminate\Queue\Events\Looping; use Illuminate\Queue\Events\WorkerStopping; use Illuminate\Support\Carbon; @@ -469,6 +470,10 @@ protected function handleJobException($connectionName, $job, WorkerOptions $opti // another listener (or this same one). We will re-throw this exception after. if (! $job->isDeleted() && ! $job->isReleased() && ! $job->hasFailed()) { $job->release($this->calculateBackoff($job, $options)); + + $this->events->dispatch(new JobReleasedAfterException( + $connectionName, $job + )); } }