在本文中,我们将介绍 Laravel Web 框架的一项令人兴奋的功能——任务调度。我们将了解 Laravel 如何允许您管理应用程序中的计划任务。此外,我们最终还将创建自己的自定义计划任务以用于演示目的。
Laravel 框架允许您设置计划任务,这样您就不必担心在系统级别设置它们。您可以在设置计划任务时摆脱复杂的 cron 语法,因为 Laravel 允许您以用户友好的方式定义它们。
我们将首先介绍如何设置传统的 cron 作业,然后我们将探索 Laravel 实现它的方式。在本文的后半部分,我们将通过创建几个自定义计划任务来尝试一下,这些任务应该提供对该主题的实际洞察。
传统计划任务设置
在日常应用程序开发中,您经常需要定期执行某些脚本或命令。如果您使用 *nix 系统,您可能知道 cron 作业处理这些命令。另一方面,它们在基于 Windows 的系统上被称为计划任务。
让我们快速浏览一下基于 *nix 的 cron 作业的简单示例。
*/5 * * * * /web/statistics.sh
非常简单——它每五分钟运行一次statistics.sh文件!
虽然这是一个非常简单的示例,但您通常需要实现更复杂的用例。复杂的系统要求您定义以不同时间间隔运行的多个 cron 作业。
让我们看看复杂的 Web 应用程序必须在后端定期执行的一些任务。
- 清理数据库后端不需要的数据。
- 更新前端缓存索引以保持最新。
- 计算网站统计信息。
- 发送电子邮件。
- 备份不同的网站元素。
- 生成报告。
- 还有更多。
正如您所看到的,有很多东西等待定期并且以不同的时间间隔运行。如果您是经验丰富的系统管理员,则可以轻松地为所有这些任务定义 cron 作业,但有时我们作为开发人员希望有一种更简单的方法。
幸运的是,Laravel 附带了一个内置的任务调度 API,它允许您以前所未有的方式定义计划任务。是的,下一节就是关于 Laravel 任务调度的基础知识。
Laravel 之道
在前面的部分中,我们介绍了设置 cron 作业的传统方法。在本节中,我们将在任务调度 API 的上下文中详细介绍 Laravel。
在我们继续之前,需要了解的重要一点是 Laravel 提供的调度功能就像任何其他功能一样,不会自动调用。因此,如果您认为不需要在系统级别执行任何操作,那么我想说您就不走运了。
事实上,如果您希望使用 Laravel 调度系统,您应该做的第一件事就是设置每分钟运行一次的 cron 作业,并调用以下代码片段中显示的 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 允许您通过多种不同的方式定义计划任务:
- 使用闭包/可调用。
- 调用
artisan
命令。 - 执行 shell 命令。
此外,还有大量内置的调度频率可供您选择:
- 每分钟/每五分钟
- 每小时/每天/每周/每季度/每年
- 一天中的特定时间
- 还有更多
事实上,我想说它提供了一套完整的例程,因此您无需接触 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 不应该运行同一任务的另一个实例。默认情况下,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 Web 框架中的任务调度 API。看到它如何轻松地管理需要定期运行的任务真是令人着迷。
在文章的开头,我们讨论了传统的设置计划任务的方式,接下来我们介绍了 Laravel 的设置方式。在本文的后半部分,我们通过几个实际示例来演示任务调度概念。
我希望您喜欢这篇文章,并且您应该对在 Laravel 中设置计划任务更有信心。对于那些刚刚开始使用 Laravel 或希望通过扩展来扩展您的知识、网站或应用程序的人,我们在 Envato Market 上提供了多种您可以学习的内容。
以上就是重写后的标题为:Laravel中的任务调度的详细内容,更多请关注php中文网其它相关文章!