教程 > laravel 教程 > 阅读:145

laravel 任务调度——迹忆客-ag捕鱼王app官网

简介

过去,我们可能已经为需要在服务器上安排的每个任务生成了一个 cron 条目。但是,这很快就会变得很痛苦,因为我们的任务计划不再受源代码控制,必须通过 ssh 连接到服务器以添加额外的 cron 条目。

laravel 的命令调度器允许在 laravel 本身中流畅而富有表现力地定义你的命令调度。使用调度程序时,服务器上仅需要一个cron条目。我们的任务计划在app/console/kernel.php文件的schedule方法中定义。为了帮助我们入门,在该方法中定义了一个简单的示例。

开启调度器

下面是我们唯一需要添加到服务器的 cron 条目,如果不知道如何添加 cron 条目到服务器,可以考虑使用诸如 laravel forge 这样的服务来为管理 cron 条目:

* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1

cron 将会每分钟调用一次 laravel 命令调度器,当 schedule:run 命令执行后,laravel 评估你的调度任务并运行到期的任务。


定义调度

我们可以在 app\console\kernel 类的 schedule 方法中定义所有调度任务。让我们从一个调度任务的例子开始,在这个例子中,我们将会在每天午夜调度一个被调用的闭包。在这个闭包中我们将会执行一个数据库操作来清空表:

call(function () {
            db::table('recent_users')->delete();
        })->daily();
    }
}

除了使用闭包进行调度之外,还可以使用可调用对象。可调用对象是包含 __invoke 方法的简单 php 类:

$schedule->call(new deleterecentusers)->daily();

调度 artisan 命令

除了调度闭包调用外,还可以调度 artisan 命令和操作系统命令。例如,可以使用 command 方法通过命令名或类来调度一个 artisan 命令:

$schedule->command('emails:send --force')->daily();
$schedule->command(emailscommand::class, ['--force'])->daily();

调度队列任务

job 方法可用于调度一个队列任务,通过该方法可以很方便地调度任务而不必调用 call 方法手动创建闭包来推送任务到队列:

$schedule->job(new heartbeat)->everyfiveminutes();
// dispatch the job to the "heartbeats" queue...
$schedule->job(new heartbeat, 'heartbeats')->everyfiveminutes();

调度 shell 命令

exec 方法可用于调用操作系统命令:

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

调度常用选项

当然,我们可以分配多种调度到任务:

方法 描述
->cron('* * * * *'); 在自定义cron调度上运行任务
->everyminute(); 每分钟运行一次任务
->everytwominutes(); 每两分钟运行一次任务
->everythreeminutes(); 每三分钟运行一次任务
->everyfourminutes(); 每四分钟运行一次任务
->everyfiveminutes(); 每五分钟运行一次任务
->everytenminutes(); 每十分钟运行一次任务
->everyfifteenminutes(); 每十五分钟运行一次任务
->everythirtyminutes(); 每三十分钟运行一次任务
->hourly(); 每小时运行一次任务
->hourlyat(17); 每小时第十七分钟运行一次任务
->everytwohours(); 每隔两个小时运行一次
->everythreehours(); 每隔三个小时运行一次
->everyfourhours(); 每隔四个小时运行一次
->everysixhours(); 每隔六个小时运行一次
->daily(); 每天凌晨零点运行任务
->dailyat('13:00'); 每天13: 00运行任务
->twicedaily(1, 13); 每天1:00 & 13: 00运行任务
->weekly(); 每周运行一次任务
->weeklyon(1, '8:00'); 每周一上午8点运行一次任务
->monthly(); 每月运行一次任务
->monthlyon(4, '15:00'); 每月4号15: 00运行一次任务
->lastdayofmonth('15:00'); 每月最后一天的15:00 运行一次
->quarterly(); 每个季度运行一次
->yearly(); 每年运行一次
->timezone('america/new_york'); 设置时区

这些方法可以和额外的约束一起联合起来创建一周特定时间运行的、更加细粒度的调度,例如,要在每周一调度一个命令:

$schedule->call(function () {
    // 每周星期一13:00运行一次...
})->weekly()->mondays()->at('13:00');
// 工作日的上午8点到下午5点每小时运行...
$schedule->command('foo')
         ->weekdays()
         ->hourly()
         ->timezone('america/chicago')
         ->between('8:00', '17:00');

下面是额外的调度约束列表:

方法 描述
->weekdays(); 只在工作日运行任务
->weekends(); 只在周末运行任务
->sundays(); 每个星期天运行任务
->mondays(); 每个星期一运行任务
->tuesdays(); 每个星期二运行任务
->wednesdays(); 每个星期三运行任务
->thursdays(); 每个星期四运行任务
->fridays(); 每个星期五运行任务
->saturdays(); 每个星期六运行任务
->days(array mixed);
->between($start, $end); 基于特定时间段运行任务
->when(closure); 基于特定测试运行任务
->environments($env); 只在指定环境运行任务
#### 日期限制

days方法可用于将任务的执行限制为一周中的特定天数。例如,可以安排一个命令在星期日和星期三每小时运行一次:

$schedule->command('reminders:send')
                ->hourly()
                ->days([0, 3]);

介于时间的约束条件

between 方法用于限定一天中特定时间段的任务执行:

$schedule->command('reminders:send')
         ->hourly()
         ->between('7:00', '22:00');

类似地,unlessbetween 方法用于排除指定时间段任务的执行:

$schedule->command('reminders:send')
         ->hourly()
         ->unlessbetween('23:00', '4:00');

真值测试的约束条件

when 方法用于限制任务基于给定真理测试的结果执行。换句话说,如果给定闭包返回true,只要没有其它约束条件阻止任务运行,该任务就会执行:

$schedule->command('emails:send')->daily()->when(function () {
    return true;
});

skip 方法和 when 相反,如果 skip 方法返回true,调度任务将不会执行:

$schedule->command('emails:send')->daily()->skip(function () {
    return true;
});

使用 when 方法链的时候,调度命令将只会执行返回 true 的 when 方法。

运行环境约束

environments 方法可用于只在给定环境执行任务:

$schedule->command('emails:send')
        ->daily()
        ->environments(['staging', 'production']);

时区

使用 timezone 方法可以指定调度任务的执行时间在给定时区内切换:

$schedule->command('report:generate')
     ->timezone('america/new_york')
     ->at('02:00')

如果我们想为所有调度任务分配了同样的时区,可以在 app/console/kernel.php 文件中定义一个 scheduletimezone 方法。该方法返回分配给所有调度任务的默认时区:

/**
 * get the timezone that should be used by default for scheduled events.
 *
 * @return \datetimezone|string|null
 */
protected function scheduletimezone()
{
    return 'america/chicago';
}

注:请记住有些时区会使用夏令时,当夏令时改变时,你的调度任务有可能会运行两次或者根本不会运行,因此,建议你最好不要使用这种时区调度。

避免任务重叠

默认情况下,即使前一个任务仍然在运行调度任务也会运行,要避免这样的情况,可使用 withoutoverlapping 方法:

$schedule->command('emails:send')->withoutoverlapping();

在本例中,artisan 命令 emails:send 每分钟都会运行 —— 如果该命令没有在运行的话。如果你的任务在执行时经常大幅度的变化,那么 withoutoverlapping 方法就非常有用,你不必再去预测给定任务到底要消耗多长时间。

如果需要的话,我们可以指定"without overlapping"锁失效前的分钟数,默认情况下,这个锁会在 24 小时后失效:

$schedule->command('emails:send')->withoutoverlapping(10);

在单台服务器上运行任务

注:要使用这个功能,必须使用 memcached 或 redis 缓存驱动作为应用默认的缓存驱动。此外,所有服务器必须和同一个中央缓存服务器通信。

如果应用运行在多台服务器上,可能需要限制调度任务只在某台服务器上运行。例如,假设我们有一个每个星期五晚上生成新报告的调度任务,如果任务调度器运行在三台服务器上,调度任务会在三台服务器上运行并且生成三次报告,不够优雅!

要告知任务只在单台服务器上运行,在定义调度任务时使用 ononeserver 方法即可。第一台获取到该任务的服务器会给任务上一把原子锁以阻止其他服务器同时运行该任务:

$schedule->command('report:generate')
            ->fridays()
            ->at('17:00')
            ->ononeserver();

后台任务

默认情况下,同时调度的多个命令会顺序执行。如果你有一些长时间运行的命令,将会导致随后的命令在预期之后很久才能执行。如果你想要让命令在后台执行以便它们可以同时运,可以使用 runinbackground 方法来实现:

$schedule->command('analytics:report')
     ->daily()
     ->runinbackground();

注:runinbackground 方法只有在通过 commandexec 方法调度任务时才可以使用。

维护模式

当 laravel 处于维护模式时,调度任务不会运行,不过,如果你想要在维护模式期间强制运行任务,可以使用 eveninmaintenancemode 方法:

$schedule->command('emails:send')->eveninmaintenancemode();

任务输出

laravel 调度器为处理调度任务输出提供了多个方便的方法。首先,使用sendoutputto 方法,你可以发送输出到文件以便稍后检查:

$schedule->command('emails:send')
     ->daily()
     ->sendoutputto($filepath);

如果想要追加输出到给定文件,可以使用 appendoutputto 方法:

$schedule->command('emails:send')
     ->daily()
     ->appendoutputto($filepath);

使用 emailoutputto 方法,我们可以将输出通过邮件发送给接收人。使用邮件发送任务输出之前,需要配置 laravel 的邮件服务:

$schedule->command('foo')
     ->daily()
     ->sendoutputto($filepath)
     ->emailoutputto('foo@example.com');

如果想要在命令执行失败时输出邮件,可以使用 emailoutputonfailure 方法:

$schedule->command('foo')
         ->daily()
         ->emailoutputonfailure('foo@example.com');

注:emailoutputto、emailoutputonfailure、sendoutputto 和 appendoutputto 方法只对 command 和 exec 方法有效。


任务钩子

使用 beforeafter 方法,你可以指定在调度任务完成之前和之后要执行的代码:

$schedule->command('emails:send')
         ->daily()
         ->before(function () {
             // task is about to start...
         })
         ->after(function () {
             // task is complete...
         });

onsuccessonfailure 方法允许你在调度任务成功或失败的情况下执行指定的代码:

$schedule->command('emails:send')
     ->daily()
     ->onsuccess(function () {
         // the task succeeded...
     })
     ->onfailure(function () {
         // the task failed...
     });

ping url

使用 pingbeforethenping方法,调度器可以在任务完成之前和之后自动 ping 给定的 url。该方法在通知外部服务时很有用,例如 laravel envoyer,在调度任务开始或完成的时候:

$schedule->command('emails:send')
         ->daily()
         ->pingbefore($url)
         ->thenping($url);

使用 pingbefore($url)thenping($url) 方法可用于只有在给定条件为 true 时才 ping 给定的 url:

$schedule->command('emails:send')
         ->daily()
         ->pingbeforeif($condition, $url)
         ->thenpingif($condition, $url);

pingonsuccesspingonfailure 方法可用于在任务成功或失败的情况下 ping 指定的 url:

$schedule->command('emails:send')
     ->daily()
     ->pingonsuccess($successurl)
     ->pingonfailure($failureurl);

所有这些 ping 方法都需要安装 http 库 guzzle,可以使用 composer 包管理器来安装 guzzle 依赖到项目:

$ composer require guzzlehttp/guzzle

查看笔记

扫码一下
查看教程更方便
网站地图