Use supervisor to monitor the jobs in the queue,
php artisan queue:listen --timeout=0
use
php artisan queue:failed-table
Failed queue records have been established, but the current situation is that failed ones are always executed repeatedly and are not written to failed_job
There is
in laravel documentationphp artisan queue:listen connection-name --tries=3
What does connection-name refer to?
php artisan queue:listen --timeout=0 --tries=3, queue execution error
exception 'Swift_TransportException' with message 'Expected response code 250 but got code "", with message ""'
How to solve these problems?
高洛峰2017-05-16 16:58:46
You can choose from a variety of queue services in laravel, the common ones are redis and beanstalk. Since redis is a simple db, the data is completely transparent, so it will be easier to understand if redis is used as the explanation object here.
The way to start the queue in laravel is the queue:listen
和queue:work
, 其中queue:work
表示单独运行下一个job. 关于区别请看:queue:listen 和 queue:work --daemon 的区别 。queue:listen
内部也是一次次的调用queue:work
实现的,现在我们来看work
command.
In IlluminateQueueConsoleWorkCommand
中是不是看见了我们熟悉的fire
method? That's it. Keep chasing,
Call the runWork
方式查找job并且执行.这里有一个daemon
option to indicate whether to run as a daemon. Directly consider daemon as false (because daemon is actually a while(true)):joy:.
See runWork
其实是调用的IlluminateQueueWorker::pop
method
public function pop($connectionName, $queue = null, $delay = 0, $sleep = 3, $maxTries = 0)
{
$connection = $this->manager->connection($connectionName); //这里就是你说的连接名称,实际就是选择一个合理的queue服务,只要你没有用某个队列服务的特有的方法,那么各个队列可以随时切换使用的.
$job = $this->getNextJob($connection, $queue); //查找一个job对象
// If we're able to pull a job off of the stack, we will process it and
// then immediately return back out. If there is no job on the queue
// we will "sleep" the worker for the specified number of seconds.
if ( ! is_null($job))
{
//如果job存在则执行任务
return $this->process(
$this->manager->getName($connectionName), $job, $maxTries, $delay
);
}
$this->sleep($sleep);
return ['job' => null, 'failed' => false];
}
Arrived at the final execution position of the job (deleted the blank lines and comments, because I am going to write crappy Chinese comments. (Escape):
public function process($connection, Job $job, $maxTries = 0, $delay = 0)
{
if ($maxTries > 0 && $job->attempts() > $maxTries){ //看见了吗,运行的时候先查看了job的执行次数如果超过了最大次数,则直接进入logFailedJob过程,也就是将失败的job存储到指定的数据库中, 观察`Illuminate\Queue\Jobs\RedisJob`中的`attempts `方法和`release`方法。一个查看attempts次数,一个增加attempts次数(当然release还有其他操作).那么找找谁调用了release方法(看下面的trycatch,就是在出现异常之后并且job没有被删除的情况下会调用release)?如果没有抛出异常?那么attempts是不会变化的。
return $this->logFailedJob($connection, $job);
}
try{
$job->fire();// job的fire方法实际已经将我们指定的JobClass用Container::make并且执行了fire方法.
if ($job->autoDelete()) $job->delete();
return ['job' => $job, 'failed' => false];
} catch (\Exception $e){
if ( ! $job->isDeleted()) $job->release($delay);
throw $e;
}
}
Well, that’s pretty much it.
The Swift_TransportException
是发送邮件程序swiftmailer
error you threw
phpcn_u15822017-05-16 16:58:46
In the connections configuration in config/queue.php, sync, beanstalkd, sqs, etc. are the connection-name.