主要介绍下 Console 内核与下面两者的使用:

  • Artisan
  • Job

Console 内核

首先理解 app/Console/Kernel 的作用

$commands 属性定义了手动加载的命令

protected $commands = [
    Commands\ReserveExpired::class,
    Commands\TestCommand::class
];

commands() 方法中引入自动加载命令的文件

protected function commands()
{
    require base_path('routes/console.php');
}

schedule() 方法中定义定时任务

有如下几种方式:

  1. Closure 闭包

    $schedule->call(function () {
        DB::table('should_delete')->delete();
    })->daily();
  2. Shell 命令

    $schedule->exec('node /home/forge/script.js')->daily();
  3. Artisan

    $schedule->command('reserve-expired')->dailyAt('02:00');
  4. Job

    $schedule->job(new ReceiveMoney)->everyFiveMinutes();

Artisan

新建一个预约已过期命令:

php artisan make:command ReserveExpired

命令结构如下

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Reserve;

class ReserveExpired extends Command
{
    //使用时期望输入的命令
    protected $signature = 'reserve-expired';

    //命令描述
    protected $description = 'change expired reserve state';

    //主方法
    public function handle()
    {
        $reserve = new Reserve();
        $reserve->updateStateWhenExpired();
    }
}

获取输入

$name = $this->ask('What is your name?');
$password = $this->secret('What is the password?');

请求确认

if ($this->confirm('Do you wish to continue?')) {
    //
}

颜色

$this->info('Success');
$this->error('Fail');
$this->line('Hello world');

定义输入期望

signature 属性中定义期望用户输入的内容

  • 花括号 {} 为必须
  • 加问号 {?} 为可选
  • 加等号 {=xx} 为带默认值的可选
protected $signature = 'wechat-menu {type?} {officialType?}';

当输入不符合时,直接返回提示信息:

$usageString = <<<USAGE
Usage: wechat-menu [options] [officialType]

       options         args: create/get
       officialType    args: one/two/three
USAGE;
$this->info($usageString);

Queue

本次选择阿里云上提供的 RocketMQ,并使用 freyo/laravel-queue-rocketmq

config/queue.php
'connections' => [ 'rocketmq' => [ 'driver' => 'rocketmq', 'access_key' => env('ROCKETMQ_ACCESS_KEY'), 'access_id' => env('ROCKETMQ_ACCESS_ID'), 'endpoint' => env('ROCKETMQ_ENDPOINT'), 'instance_id' => env('ROCKETMQ_INSTANCE_ID'), 'group_id' => env('ROCKETMQ_GROUP_ID'), 'queue' => env('ROCKETMQ_QUEUE'), 'use_message_tag' => env('ROCKETMQ_USE_MESSAGE_TAG', false), 'wait_seconds' => env('ROCKETMQ_WAIT_SECONDS', 0), 'plain' => [ 'enable' => false, 'job' => 'App\Jobs\RocketMQPlainJobHandler@handle', ], ], ],

创建任务

php artisan make:job ReceiveMoney

在构造类中声明需要接收的参数,使用 dispatch 分发它,并指定队列:

ReceiveMoney::dispatch($data, $type)->onQueue(env('ROCKETMQ_TOPIC_JOB'));

运行队列

# 常驻
php artisan queue:work
# 单次
php artisan queue:work --once

失败处理

failed 配置队列中的任务执行失败时,保存失败任务的库与表,并用命令创建:

php artisan queue:failed-table
php artisan migrate

手动查看与操作失败任务:

# 以表格展示
php artisan queue:failed
# 重试单个ID
php artisan queue:retry 1
# 重试全部
php artisan queue:retry all
# 删除单个ID
php artisan queue:forget 2
# 删除全部
php artisan queue:flush

在运行时指定自动重试次数 --tries,例如 3 次:

php artisan queue:listen --queue=common --tries=3

在类中定义一个重试时间方法,例如第一次 10 秒,第二次 1 分钟,第三次 5 分钟:

public function backoff()
{
    return [10, 60, 300];
}

完整的运行示例:

php artisan queue:listen --queue=common --delay=1 --sleep=3 --tries=3 --timeout=600 --quiet | bash >> /var/log/message_common.log 2>&1

平时在遇到数据延迟时要及时查看队列状态