使用supervisor监听队列的job,
php artisan queue:listen --timeout=0
使用
php artisan queue:failed-table
建立了失败的队列记录,但是现状是失败的总是在重复执行,并没有写入到failed_job
laravel文档中有
php artisan queue:listen connection-name --tries=3
connection-name指的是什么?
php artisan queue:listen --timeout=0 --tries=3时,队列执行报错
exception 'Swift_TransportException' with message 'Expected response code 250 but got code "", with message ""'
这些问题该怎么解决?
高洛峰2017-05-16 16:58:46
在laravel中可以选择多种队列服务,常见的有redis和beanstalk,由于redis是单纯的db,数据完全透明所以这里用redis作为讲解对象会更加好理解。
laravel中队列的启动方式有queue:listen
和queue:work
, 其中queue:work
表示单独运行下一个job. 关于区别请看:queue:listen 和 queue:work --daemon 的区别 。queue:listen
内部也是一次次的调用queue:work
实现的,现在我们来看work
命令。
在IlluminateQueueConsoleWorkCommand
中是不是看见了我们熟悉的fire
方法?对就是它。继续追,
调用runWork
方式查找job并且执行.这里有一个daemon
选项, 表示是否作为守护运行。直接将daemon认为false(因为daemon其实就是一个while(true) ):joy:。
看到runWork
其实是调用的IlluminateQueueWorker::pop
方法
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];
}
到了最终执行job的位置(删掉了空行和注释,因为我要来上蹩脚的中文注释了.(逃 ):
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;
}
}
恩,差不多就是这么回事了。
你那个抛出来的Swift_TransportException
是发送邮件程序swiftmailer
抛出的错误
phpcn_u15822017-05-16 16:58:46
config/queue.php里的connections配置中,sync,beanstalkd,sqs等就是那个connection-name。