* { box-sizing: border-box; } body {margin: 0;}
在这篇文章中, 我们将通过Laravel网络框架的一个令人兴奋的功能 - 任务调度.在这篇文章的过程中, 我们将看看Laravel是如何让你在你的应用程序中管理预定的任务。此外, 我们也会在最后创建我们自己的自定义计划任务来进行演示.
Laravel框架允许你设置计划任务, 这样你就不必担心在系统层面上设置它们了.你可以在设置计划任务时摆脱复杂的cron语法,因为Laravel允许你以一种用户友好的方式定义它们。
我们将在文章的开头介绍你习惯于如何设置传统的cron作业, 接下来我们将探讨Laravel的实现方式。在文章的后半部分, 我们将通过创建几个自定义的计划任务来试一试,以提供对该主题的实践洞察力。
传统的计划任务设置
在你的日常应用开发中,你经常面临需要定期执行某些脚本或命令的情况。如果你使用的是*nix系统,你可能知道cron jobs处理这些命令。另一方面,它们在基于Windows的系统中被称为计划任务。
让我们快速看一下基于*nix的cron job的一个简单例子。
*/5 * * * * /web/statistics.sh
很简单--它每五分钟运行一次statistics.sh文件!
虽然这是一个相当简单的用例,但你经常发现自己处于一个需要你实现更复杂用例的情况。另一方面,一个复杂的系统需要你定义多个cron job,在不同的时间间隔内运行。
让我们看看一个复杂的网络应用程序在后端必须定期执行的一些任务。
- 从数据库后端清理不必要的数据。
- 更新前端的缓存索引,使其保持最新状态。
- 计算网站的统计数据。
- 发送电子邮件。
- 备份不同的网站元素。
- 生成报告。
- 还有更多。
因此,正如你所看到的,有很多东西在那里等待着定期运行,也在不同的时间间隔内运行。如果你是一个经验丰富的系统管理员, 对你来说为所有这些任务定义cron jobs是小菜一碟, 但有时我们作为开发者希望有一个更简单的方法.
幸运的是, Laravel有一个内置的任务调度API,让你可以像以前一样定义计划任务。是的, 下一节就是关于这个--Laravel任务调度的基础知识.
拉威尔的方式
在前面的章节中, 我们经历了传统的设置cron jobs的方式.在这一节中, 我们将通过Laravel在任务调度API方面的具体情况.
在我们继续之前, 需要了解的是, Laravel提供的调度功能就像其他功能一样, 不会被自动调用.因此,如果你认为你不需要在系统层面上做任何事情,那么你就不走运了,我想说。
事实上, 如果你想使用Laravel调度系统, 你应该做的第一件事就是设置cron job, 每分钟运行一次, 并调用下面片段中的artisan 命令.
* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
上面的artisan 命令会调用Laravel调度系统, 而这又会执行你的应用程序中定义的所有待定的cron作业.
当然, 我们还没有看到如何在你的Laravel应用程序中定义计划任务, 这就是我们接下来要深入研究的事情.
这是App\Console\Kernel 类的schedule 方法, 如果你想定义特定的应用程序的计划任务, 你需要使用这个方法.
继续并抓取app/Console/Kernel.php文件的内容。
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
//
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')->hourly();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
正如你所看到的, 核心代码本身提供了一个有用的例子.在上面的例子中, Laravel每小时运行inspire artisan 命令.你不觉得这个语法首先是很直观的吗?
事实上, Laravel允许你用几种不同的方式来定义日程任务:
- 使用closure/callable.
- 调用
artisan命令. - 执行shell命令.
此外, 有很多内置的调度频率可以让你选择:
- 每分钟/每5分钟
- 每小时/每天/每周/每季度/每年
- 在一天中的某个特定时间
- 以及更多
事实上,我想说的是,它提供了一套完整的例程,这样你就不需要再去接触shell来创建你的自定义cron作业了
是的,我可以告诉你,你很想知道如何实现你的自定义计划任务,这也是我在文章开头承诺的。
在Laravel中创建你的第一个计划任务
正如我们所讨论的, Laravel允许你用不同的方式来定义计划任务.让我们通过每一种方式来了解它是如何工作的。
闭合/可调用方法
调度API提供了call 方法,允许你执行一个可调用或封闭的函数。让我们用下面的代码修改一下app/Console/Kernel.php文件。
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Illuminate\Support\Facades\DB;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
//
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// the call method
$schedule->call(function () {
$posts = DB::table('posts')
->select('user_id', DB::raw('count(*) as total_posts'))
->groupBy('user_id')
->get();
foreach($posts as $post)
{
DB::table('users_statistics')
->where('user_id', $post->user_id)
->update(['total_posts' => $post->total_posts]);
}
})->everyThirtyMinutes();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
正如你所看到的,我们已经将封闭函数作为call 方法的第一个参数。另外,我们将频率设置为每30分钟一次,所以它将每30分钟执行一次闭合函数!
在我们的例子中,我们计算每个用户的帖子总数,并相应地更新statistics 表。
artisan 命令
除了闭合函数或可调用函数之外,你还可以安排一个artisan 命令,在一定的时间间隔内执行。事实上,这应该是比闭包更受欢迎的方法,因为它同时提供了更好的代码组织和可重用性。
继续修改app/Console/Kernel.php文件的内容,内容如下。
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Illuminate\Support\Facades\DB;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
'App\Console\Commands\UserStatistics'
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('statistics:user')->everyThirtyMinutes();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
这是command 方法,如果你想安排一个artisan 命令,你要使用这个方法,如上面的代码片段所示。你需要传递一个artisan 命令签名作为command 方法的第一个参数。
当然,你也需要在app/Console/Commands/UserStatistics.php定义相应的artisan 命令。
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class UserStatistics extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'statistics:user';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Update user statistics';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// calculate new statistics
$posts = DB::table('posts')
->select('user_id', DB::raw('count(*) as total_posts'))
->groupBy('user_id')
->get();
// update statistics table
foreach($posts as $post)
{
DB::table('users_statistics')
->where('user_id', $post->user_id)
->update(['total_posts' => $post->total_posts]);
}
}
}
exec 命令
我们可以说,到目前为止,我们所讨论的方法是针对Laravel应用程序本身的。此外, Laravel也允许你安排shell命令,这样你也可以运行外部应用程序。
让我们来看看一个快速的例子, 它演示了如何每天对你的数据库进行备份。
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// exec method
$host = config('database.connections.mysql.host');
$username = config('database.connections.mysql.username');
$password = config('database.connections.mysql.password');
$database = config('database.connections.mysql.database');
$schedule->exec("mysqldump -h {$host} -u {$username} -p{$password} {$database}")
->daily()
->sendOutputTo('/backups/daily_backup.sql');
}
}
从代码中可以看出,你需要使用调度器的exec 方法,你需要传递你想运行的命令作为它的第一个参数。
除此以外,我们还使用了sendOutputTo 方法,该方法允许你收集命令的输出。另一方面,还有一个方法,emailOutputTo ,它允许你用电子邮件发送输出内容
这就把我们带到了文章的结尾。事实上, 我们只是触及了Laravel调度API的表面, 它有很多东西可以提供。
如何防止任务重叠
在这一节中, 我们将看到你如何防止任务的重叠.如果你已经定义了一个任务, 你想确保如果它已经在运行, Laravel不应该再运行同一个任务的实例.默认情况下, Laravel总是会开始运行计划中的任务, 即使同一个任务的前一个实例已经在运行并且还没有完成.
所以让我们看看你如何避免计划任务的重叠。
$schedule->command('statistics:user')->everyThirtyMinutes()->withoutOverlapping();
正如你所看到的, 你只需要使用withoutOverlapping 方法来确保Laravel不会与已经运行的任务重叠。默认情况下, 锁定时间是在Laravel重叠任务前的24小时。如果你想覆盖它, 你可以像下面的片段那样做。
$schedule->command('statistics:user')->everyThirtyMinutes()->withoutOverlapping(30);
在上面的例子中, Laravel等待了30分钟才清除重叠的锁.
如何定义后台任务
如果你在同一时间安排多个任务, Laravel会按顺序运行它。所以,如果你有一个任务需要很长的时间来执行,那么下一个安排的任务就必须等待很长的时间。为了避免这种情况, 你可以在后台执行这些任务.
让我们快速看一下下面的例子,看看如何定义一个后台任务。
$schedule->command('statistics:user')->daily()->runInBackground();
正如你所看到的,你可以使用runInBackground 方法来定义一个后台任务。
总结
今天, 我们经历了Laravel网络框架中的任务调度API.看到它是如何轻松地让你管理需要定期运行的任务,这很吸引人。
在文章的开头,我们讨论了传统的设置计划任务的方式,接下来我们介绍了Laravel的方式。在文章的后半部分, 我们通过几个实际的例子来展示任务调度的概念.
我希望你喜欢这篇文章, 而且你应该对在Laravel中设置预定任务感到更有信心.对于那些刚刚开始使用Laravel的人,或者希望通过扩展来扩展你的知识,网站或应用程序的人,我们在Envato市场有各种可以学习的东西。
