Laravel队列简单实现

in 普通BLOG
0 评论 阅读量:627

背景

因业务需要,定期导入Excel表格转换为数组批量入库;当一次性导入达到近千条时,有超时风险(过慢的反应时间,客户也是不接受的)

实现

创建任务

$ php artisan make:job ProcessExcel

传递变量到构造函数,后续在handle中处理,handle中也可注入依赖类随时调用

app/Jobs/ProcessExcel.php

class ProcessExcel implements ShouldQueue, ShouldBeUnique
{
    /**
     * Create a new job instance.
     * @params 传递的参数
     * @return void
     */
    public function __construct(array $row)
    {
        $this->row = $row;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle(SomeServices $services)
    {
        extract($this->row); // use params
        // do somethings
    }

在env中我们选择redis驱动

QUEUE_CONNECTION=redis

业务代码示例

ProcessExcel::dispatch($row); // 分发队列
// $services->store($row); // 摒弃services的操作

宝塔安装Supervisor,新增守护进程命令如下,启动用户使用www

/www/server/php/73/bin/php artisan queue:work --daemon

另外我们也可以适当有一些监控

app/Providers/AppServiceProvider.php

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        /* 队列处理开始 */
        Queue::before(function (JobProcessing $event) {
            // $event->connectionName
            // $event->job
            // $event->job->payload()

            $payload = $event->job->payload();
            /*
            'payload' => 
                array (
                    'uuid' => '7fc971b7-3d3d-4476-a47d-04bcbae6ac31',
                    'timeout' => 10, // 执行超时时间
                    'id' => 'M2IPb87k4hHKlWPOtfRszOmKci2xJP6J',
                    'backoff' => NULL, // 执行异常后重试前延迟的分钟数
                    'displayName' => 'App\\Jobs\\ProcessExcel', // 用于展示的别名 使用@displayName()设置
                    'maxTries' => 3, // 最大尝试次数
                    'failOnTimeout' => false, // 超时后标记为失败
                    'maxExceptions' => NULL, // 失败前允许的最大未处理异常数
                    'retryUntil' => 1655276931, // 尝试截止时间 设置为当天 次日则不再尝试当天失败任务
                    'job' => 'Illuminate\\Queue\\CallQueuedHandler@call',
                    'data' => 
                    array (
                    'command' => 'O:21:"App\\Jobs\\ProcessExcel":14:{s:7:"timeout";i:10;s:5:"tries";i:3;s:28:"' . "\0" . 'App\\Jobs\\ProcessExcel' . "\0" . 'batch";O:45:"Illuminate\\Contracts\\Database\\ModelIdentifier":4:{s:5:"class";s:23:"App\\Models\\ReportsBatch";s:2:"id";i:174;s:9:"relations";a:0:{}s:10:"connection";s:5:"mysql";}s:34:"' . "\0" . 'App\\Jobs\\ProcessExcel' . "\0" . 'report_path";s:56:"/www/wwwroot/blfy.sz17it.com/storage/app/public/reports/";s:3:"job";N;s:10:"connection";N;s:5:"queue";N;s:15:"chainConnection";N;s:10:"chainQueue";N;s:19:"chainCatchCallbacks";N;s:5:"delay";N;s:11:"afterCommit";N;s:10:"middleware";a:0:{}s:7:"chained";a:0:{}}',
                    'commandName' => 'App\\Jobs\\ProcessExcel',
                    ), // 命令的详细
                    'attempts' => 2, // 执行次数
                )
            */
        });

        /* 队列处理结束 */
        Queue::after(function (JobProcessed $event) {
            // $event->connectionName
            // $event->job
            // $event->job->payload()
        });
    }

同样支持数据表的日志记录(只保存失败记录)

php artisan queue:failed-table

其他

十分好用,客户上传表格后,无需等待处理。
以上为简单实现,有其他个性化需求可以详细查看官方文档;


参考资料

Laravel 8 中文文档 队列

Laravel 队列系统实现及使用教程

如何解决Laravel+Redis多个进程同时取队列的问题

Comments are closed.