laravle 队列

队列驱动

# 同步队列
sync
# 数据库
database
# 第三方队列服务
beanstalkd
sqs
redis
# 不使用队列
null

配置

# 任务过期 任务在执行了 90 秒后将会被放回队列而不是删除它,设置为你认为你的任务可能会执行需要最长时间
retry_after=90

生成任务表

# 队列表
php artisan queue:table
# 生成队列失败表
php artisan queue:failed-table
# 执行数据迁移
php artisan migrate

创建任务类

php artisan make:job ProcessPodcast

class ProcessPodcast implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
    //应该处理任务的队列连接.
    public $connection = 'sqs';
    
    //任务可以执行的最大秒数 (超时时间)。
    public $timeout = 120;

    //任务可以尝试的最大次数。
    public $tries = 5;
    
    //基于时间的尝试 在给定的时间范围内,任务可以无限次尝试
    public function retryUntil()
    {
        return now()->addSeconds(5);
    }
    
    //如果模型缺失即删除任务。
    public $deleteWhenMissingModels = true;

    protected $podcast;

    public function __construct(Podcast $podcast)
    {
        $this->podcast = $podcast;
    }

    // 执行任务
    public function handle(AudioProcessor $processor)
    {
        // 处理上传播客...
    }
    
    //任务失败的处理过程
    public function failed(Exception $exception)
    {
        // 给用户发送任务失败的通知,等等……
    }
}

频率限制

# 使用 throttle 方法,你可以限制一个给定类型的任务每 60 秒只执行 10 次
Redis::throttle('key')->allow(10)->every(60)->then(function () {
    // 任务逻辑...
}, function () {
    // 无法获得锁...

    return $this->release(10);
});

# 可以限制一个给定类型的任务一次只能执行一个处理器
Redis::funnel('key')->limit(1)->then(function () {
    // 任务逻辑...
}, function () {
    // 无法获得锁...

    return $this->release(10);
});

分发任务

$job=new \App\Jobs\ProcessPodcast(\Illuminate\Support\Facades\Auth::user());
dispatch($job);

\App\Jobs\ProcessPodcast::dispatch(['name' =>'yanjiaqing']);

# 延迟10分钟分发
 ProcessPodcast::dispatch($podcast)->delay(now()->addMinutes(10));

# 同步调度 队列任务将不会排队,并立即在当前进程中运行
 ProcessPodcast::dispatchNow($podcast);
 
# 分发任务到指定连接
ProcessPodcast::dispatch($podcast)->onConnection('sqs');

# 分发任务到指定队列
 ProcessPodcast::dispatch($podcast)->onQueue('processing');
 
# 排队闭包
$podcast = App\Podcast::find(1);
dispatch(function () use ($podcast) {
    $podcast->publish();
});

# 队列优先级
dispatch((new Job)->onQueue('high'));

链连接和队列

ProcessPodcast::withChain([
    new OptimizePodcast,
    new ReleasePodcast
])->dispatch()->allOnConnection('redis')->allOnQueue('podcasts');

任务执行前后的处理

# App/Providers/AppServiceProvider 
public function boot()
{
      Queue::before( function (JobProcessing $event) {
            $event->connectionName
            $event->job
            $event->job->payload()
          Log::info("处理任务前");
      });
      Queue::after( function (JobProcessed $event) {
          Log::info("处理任务后");
      });
      
      # 任务失败事件
      Queue::failing(function (JobFailed $event) {
            // $event->connectionName
            // $event->job
            // $event->exception
        });
}

运行队列处理器

php artisan queue:work redis --queue=emails

# 指定链接
redis
# 指定队列
emails
# 只处理队列中的单一任务。
--once
# 处理所有队列的任务然后退出 docker容器好用
--stop-when-empty
# 要运行一个处理器来确认 low 队列中的任务在全部的 high 队列任务完成后才继续执行
--queue=high,low
# 处理器超时 短于retry_after 配置项
--timeout=60
# 队列进程睡眠时间
--sleep=3
# 最大尝试次数
--tries=3
# 以守护进程模式运行工作程序(不推荐)
--daemon
# 延迟失败作业的时间量
--delay=0
# 强制工人在维护模式下运行
--force
# 内存限制(以兆字节为单位)
--memory=128

重试失败的任务

# 查看所有被放入 failed_jobs 数据表中的任务
php artisan queue:failed

# 要重试一个任务 ID 为 5 的任
php artisan queue:retry 5

# 要重试所有失败的任务,执行 queue:retry 命令
php artisan queue:retry all

# 如果你想删除一个失败的任务
php artisan queue:forget 5

# 要清空所有失败的任务
php artisan queue:flush


队列处理器 & 部署

php artisan queue:restart

三种消费队列方式

1 queue:work - 这是一个新的后台进程(不再需要 daemon 标记), 这种方式运行,框架只会启动一次,并保持循环去消费队列,除非出现异常否则该进程将无限时间运行下去。这种方式消耗的 cpu 和 内存 都比 queue:listen 要少,因为在整个生命周期中框架一直是在保持运行状态。同时,使用该方法时如果更新了代码,记得使用 queue:restart 来重启。

2 queue:work --once - 该方法会启动框架,运行 job,然后销毁掉。在开发和测试代码的时候使用比较合适,因为每次都会加载一遍代码嘛。

3 queue:listen - 这种方式运行,框架每次都会启动,运行job,然后关闭,然后再次启动框架,运行job,然后关闭,这样一直循环(每次运行完一次都会完全释放掉运行时的内存和进程)。所以这种方式你不用担心代码的热更新,不用去重启 queue,随之而来的另外一个好处是不用去担心 queue:work 带来的内存泄漏。

注意 从 5.3 版本开始 --daemon 这个参数已经不再起作用了

Supervisor 安装

# ubuntu
sudo apt-get install supervisor

配置 Supervisor

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3
autostart=true
autorestart=true
user=forge
# 运行 8 个 queue:work 进程并对其进行监控
numprocs=8
redirect_stderr=true
stdout_logfile=/home/forge/app.com/worker.log

在 Queue facade 使用 looping 方法可以在处理器尝试获取任务之前执行回调

Queue::looping(function () {
    while (DB::transactionLevel() > 0) {
        DB::rollBack();
    }
});

posted on 2023-02-28 13:47  何苦->  阅读(24)  评论(0编辑  收藏  举报

导航