diff --git a/src/Illuminate/Queue/CallQueuedHandler.php b/src/Illuminate/Queue/CallQueuedHandler.php index 1df532129ddd..6047a1a3e259 100644 --- a/src/Illuminate/Queue/CallQueuedHandler.php +++ b/src/Illuminate/Queue/CallQueuedHandler.php @@ -2,6 +2,8 @@ namespace Illuminate\Queue; +use Exception; +use ReflectionClass; use Illuminate\Contracts\Queue\Job; use Illuminate\Contracts\Bus\Dispatcher; use Illuminate\Database\Eloquent\ModelNotFoundException; @@ -40,9 +42,7 @@ public function call(Job $job, array $data) $job, unserialize($data['command']) ); } catch (ModelNotFoundException $e) { - return FailingJob::handle( - $job->getConnectionName(), $job, $e - ); + return $this->handleModelNotFound($job, $e); } $this->dispatcher->dispatchNow( @@ -105,6 +105,33 @@ protected function ensureNextJobInChainIsDispatched($command) } } + /** + * Handle a model not found exception. + * + * @param \Illuminate\Contracts\Queue\Job $job + * @param \Exception $e + * @return void + */ + protected function handleModelNotFound(Job $job, $e) + { + $class = $job->resolveName(); + + try { + $shouldDelete = (new ReflectionClass($class)) + ->getDefaultProperties()['deleteWhenMissingModels'] ?? false; + } catch (Exception $e) { + $shouldDelete = false; + } + + if ($shouldDelete) { + return $job->delete(); + } + + return FailingJob::handle( + $job->getConnectionName(), $job, $e + ); + } + /** * Call the failed method on the job instance. * diff --git a/tests/Integration/Queue/CallQueuedHandlerTest.php b/tests/Integration/Queue/CallQueuedHandlerTest.php index 76b9061250aa..8db9148e9f88 100644 --- a/tests/Integration/Queue/CallQueuedHandlerTest.php +++ b/tests/Integration/Queue/CallQueuedHandlerTest.php @@ -37,6 +37,7 @@ public function test_job_is_marked_as_failed_if_model_not_found_exception_is_thr $job = Mockery::mock('Illuminate\Contracts\Queue\Job'); $job->shouldReceive('getConnectionName')->andReturn('connection'); + $job->shouldReceive('resolveName')->andReturn(__CLASS__); $job->shouldReceive('markAsFailed')->once(); $job->shouldReceive('isDeleted')->andReturn(false); $job->shouldReceive('delete')->once(); @@ -48,6 +49,27 @@ public function test_job_is_marked_as_failed_if_model_not_found_exception_is_thr Event::assertDispatched(JobFailed::class); } + + public function test_job_is_deleted_if_has_delete_property() + { + Event::fake(); + + $instance = new Illuminate\Queue\CallQueuedHandler(new Illuminate\Bus\Dispatcher(app())); + + $job = Mockery::mock('Illuminate\Contracts\Queue\Job'); + $job->shouldReceive('getConnectionName')->andReturn('connection'); + $job->shouldReceive('resolveName')->andReturn(CallQueuedHandlerExceptionThrower::class); + $job->shouldReceive('markAsFailed')->never(); + $job->shouldReceive('isDeleted')->andReturn(false); + $job->shouldReceive('delete')->once(); + $job->shouldReceive('failed')->never(); + + $instance->call($job, [ + 'command' => serialize(new CallQueuedHandlerExceptionThrower), + ]); + + Event::assertNotDispatched(JobFailed::class); + } } class CallQueuedHandlerTestJob @@ -64,6 +86,8 @@ public function handle() class CallQueuedHandlerExceptionThrower { + public $deleteWhenMissingModels = true; + public function handle() { //