说明：Job failed 只当Job处理超过一定次数，仍旧没有处理掉的。如果是处理程序异常，Job会被释放，等待下一次处理。

这里是统一的将超过处理次数的消息摘出来，从消息队列删除。防止出现大量积压。

Mark the given job as failed and remove job from queue and raise the relevant event.

@param Job        $job
@param \Exception $e
760041
protected function failJob(Job $job, $e = null)
    {
        // 将失败的消息单独处理，放入失败数据库等。
        $job->markAsFailed();
        try {
            if (!$job->isDeleted()) {
                $job->delete();
            }
        } finally {
            $this->raiseFailedJobEvent($job, $e ?: new \Exception('Job failed'));
        }
    }
476082
protected function raiseFailedJobEvent(Job $job)
	{
		$data = json_decode($job->getRawBody(), true);

		if($this->container->bound('events'))
		{
			$this->container['events']->fire('illuminate.queue.failed', array('sync', $job, $data));
		}
	}
1254720
protected function retryJob($job)
    {
        $this->app['queue']->driver($job->connector)->pushRaw(
            $this->resetAttempts($job->payload), $job->queue
        );
    }
1157639
private function failJob(JobInterface $job, Exception $reason = null, $silent = true)
    {
        if ($job_id = $job->getQueueId()) {
            $previous_attempts = $this->getPreviousAttemptsByJobId($job_id);

            $log_arguments = [
                'job_id' => $job->getQueueId(),
                'job_type' => get_class($job),
            ];

            if ($reason) {
                $log_arguments['exception'] = $reason;
            }

            if (($previous_attempts + 1) >= $job->getAttempts()) {
                $log_arguments['event'] = 'job_failed';

                if ($this->log) {
                    $log_message = 'Job #{job_id} ({job_type}) failed after {attempts} attemtps';
                    $log_arguments['attempts'] = $previous_attempts + 1;

                    if ($reason instanceof Exception) {
                        $log_message .= '. Exception: {exception}';
                    }

                    $this->log->error($log_message, $log_arguments);
                }

                $this->logFailedJob($job, ($reason instanceof Exception ? $reason->getMessage() : ''));
            } else {
                $log_arguments['event'] = 'job_attempt_failed';

                if ($this->log) {
                    $log_message = 'Job #{job_id} ({job_type}) failed at attempt {attempt}';
                    $log_arguments['attempt'] = $previous_attempts + 1;

                    if ($reason instanceof Exception) {
                        $log_message .= '. Exception: {exception}';
                    }

                    $this->log->error($log_message, $log_arguments);
                }

                $this->prepareForNextAttempt($job_id, $previous_attempts, $job->getDelay());
            }
        }

        if (!empty($this->on_job_failure)) {
            foreach ($this->on_job_failure as $callback) {
                call_user_func($callback, $job, $reason);
            }
        }

        if ($reason instanceof Exception && !$silent) {
            throw $reason;
        }
    }
1301191
public function workingOn(Job &$job)
    {
        $this->job = $job;
        $job->setWorker($this);

        Event::fire(Event::WORKER_WORKING_ON, array($this, $job));

        $this->redis->hmset(self::redisKey($this), array(
            'job_id'      => $job->getId(),
            'job_started' => microtime(true)
        ));
    }
813729
public static function handle($connectionName, $job, $e = null)
    {
        $job->markAsFailed();

        if ($job->isDeleted()) {
            return;
        }

        try {
            // If the job has failed, we will delete it, call the "failed" method and then call
            // an event indicating the job has failed so it can be logged if needed. This is
            // to allow every developer to better keep monitor of their failed queue jobs.
            $job->delete();

            $job->failed($e);

        } finally {
        }
    }
99054
public function perform(ResqueJobBase $job)
    {
        try {
            $this->resqueInstance->events->trigger('afterFork', $job);
            $result = $job->perform();
            if ($result instanceof \Exception) {
                $this->logger->log(LogLevel::CRITICAL, '{job} has failed {message} at the line {line}',
                    [
                        'job' => $job,
                        'message' => $result->getMessage(),
                        'line' => $result->getLine()
                    ]);
                return;
            }
        } catch (\Exception $e) {
            $this->logger->log(LogLevel::CRITICAL, '{job} has failed {message} at the line {line}',
                [
                    'job' => $job,
                    'message' => $e->getMessage(),
                    'line' => $e->getLine()
                ]);
            return;
        }

        $job->status->update(ResqueJobStatus::STATUS_COMPLETE);
        $this->logger->log(LogLevel::NOTICE, '{job} has finished', ['job' => $job]);
    }
1310088
protected function raiseFailedJobEvent( $connection, Job $job, $failedId )
	{
		$data = json_decode( $job->getRawBody(), true );
		Framework::hooks()->trigger( 'queue.job.failed', compact( 'connection', 'job', 'data', 'failedId' ) );
	}
1003999
public function process($connection, Job $job, $maxTries = 0, $delay = 0)
	{
		if ($maxTries > 0 && $job->attempts() > $maxTries)
		{
			return $this->logFailedJob($connection, $job);
		}

		try
		{
			// First we will fire off the job. Once it is done we will see if it will
			// be auto-deleted after processing and if so we will go ahead and run
			// the delete method on the job. Otherwise we will just keep moving.
			$job->fire();

			return ['job' => $job, 'failed' => false];
		}

		catch (Exception $e)
		{
			// If we catch an exception, we will attempt to release the job back onto
			// the queue so it is not lost. This will let is be retried at a later
			// time by another listener (or the same one). We will do that here.
			if ( ! $job->isDeleted()) $job->release($delay);

			throw $e;
		}
	}
84793
public static function fire($job, $data)
    {

        \Log::info('Queue job called #' . $job->getJobId(), Arr::toArray($data));

        $method = $data['@method'];

        unset($data['@method']);

        $t = self::getInstance();

        call_user_func_array(array($t, $method), $data);

        $job->delete();
    }
139669
protected function raiseFailedJobEvent($connectionName, $job, $e)
    {
        $this->events->dispatch(new Events\JobFailed(
            $connectionName, $job, $e
        ));
    }
506147
protected function markJobAsFailedIfAlreadyExceedsMaxAttempts(Job $job, $maxTries)
    {
        if ($maxTries === 0 || $job->attempts() <= $maxTries) {
            return;
        }

        $this->failJob($job, $e = new \RuntimeException('A queued job has been attempted too many times. The job may have previously timed out.'));

        throw $e;
    }
1129326
public function delete(Job $job)
    {
        $result = false;
        try {
            $res = $this->_queue->deleteMessage($job->getInstance()->getReceiptHandle());
            $result = $res->isSucceed();
        } catch (\Exception $e) {
            $this->eventsManager->fire('listener:logger', $this, '删除Queue消息失败:' . $e->getMessage());
        } finally {
            return $result;
        }
    }
702312
protected function raiseExceptionOccurredJobEvent($workCommand, $connectionName, $job, $e)
    {
        $workCommand->writeOutput($job, 'failed');

        $workCommand->logFailedJob(new JobFailed($connectionName, $job, $e));
    }
632449
public static function onFailure(\Exception $e, \Resque_Job $job)
    {
        /** @var JobBase $failedJob */
        $failedJob = $job->getInstance();
        $failedJob->errorLog('Caught exception in '. get_called_class() . ': ' . $e->getMessage());
        $failedJob->getStat()->increment($failedJob->getStatFailureIncrementKey());
        throw $e;
    }
694518
public function perform(Job $job)
    {
        // Set timeout so as to stop any hanged jobs
        // and turn off displaying errors as it fills
        // up the console
        set_time_limit($this->timeout);
        ini_set('display_errors', 0);

        $job->perform();

        $status = $job->getStatus();

        switch ($status) {
            case Job::STATUS_COMPLETE:
                $this->log('Done job <pop>'.$job.'</pop> in <pop>'.$job->execTimeStr().'</pop>', Logger::INFO);
                break;
            case Job::STATUS_CANCELLED:
                $this->log('Cancelled job <pop>'.$job.'</pop>', Logger::INFO);
                break;

            case Job::STATUS_FAILED:
                $this->log('Job '.$job.' failed: "'.$job->failError().'" in '.$job->execTimeStr(), Logger::ERROR);
                break;
            default:
                $this->log('Unknown job status "('.gettype($status).')'.$status.'" for <pop>'.$job.'</pop>', Logger::WARNING);
                break;
        }
    }
896099
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 $job->fail($e);
    }