Laravel中的任務調度

PHPz
發布: 2023-09-01 09:06:01
原創
1494 人瀏覽過

Laravel中的任務調度

在本文中,我們將介紹 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中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板