iT邦幫忙

2024 iThome 鐵人賽

DAY 16
0
佛心分享-IT 人自學之術

後端小白自學 Laravel系列 第 16

第 16 天:任務調度與隊列

  • 分享至 

  • xImage
  •  

介紹任務調度(Task Scheduling)


文件:任务调度
任務調度: 使用 schedule 方法定義任務的調度頻率,並透過 Cron 作業執行調度器。

Laravel 的任務排程可輕鬆定義和排程週期性任務,而無需使用系統的 Cron 作業。
使用 Laravel 的調度器來定義任務的執行頻率,並讓 Laravel 負責管理任務的執行。

創建和調度定時任務


創建任務
指令 php artisan make:command SendDailyReport 產生新的命令類,並在 app/Console/Commands/SendDailyReport.php 做任務邏輯

namespace App\Console\Commands;

use Illuminate\Console\Command;

class SendDailyReport extends Command
{
    protected $signature = 'report:daily';
    protected $description = 'Send a daily report';

    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {
        // 這裡放任務邏輯
        $this->info('Daily report sent!');
    }
}

調度任務
app/Console/Kernel.php 檔案中,定義任務調度的頻率

// app/Console/Kernel.php

protected function schedule(Schedule $schedule)
{
    // 每天晚上執行任務
    $schedule->command('report:daily')->daily();
}

要讓 Laravel 的調度器運行,需要在伺服器上設定一個 Cron 作業來每分鐘運行 Laravel 的調度器:

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

使用隊列處理異步任務(Queue)


文件:队列
佇列處理: 建立作業、設定佇列驅動、派發和處理佇列作業,最佳化應用程式的回應速度。

佇列允許將耗時的操作(如發送郵件、產生報告等)延遲處理,從而提高應用程式的回應速度。

配置隊列
.env 檔案中配置佇列驅動:

QUEUE_CONNECTION=database

運行遷移來建立隊伍列表:

php artisan queue:table
php artisan migrate

在 app/Jobs 目錄下產生一個新的作業類別檔案。編輯該文件以定義你的作業邏輯:

// app/Jobs/ProcessReport.php
namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class ProcessReport implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct()
    {
        //
    }

    public function handle()
    {
        // 這裡放任務邏輯
        \Log::info('Processing report...');
    }
}

派發佇列作業
在控制器或其他地方派發佇列作業:

use App\Jobs\ProcessReport;

// 派發佇列作業
ProcessReport::dispatch();

處理佇列
指令 php artisan queue:work,使用佇列工作進程來處理佇列作業。

總結


💡 任務調度 Task Scheduling
可以定期執行特定的任務,例如清理過期的數據或發送電子郵件。Laravel 提供了一個方便的 API 來設定和管理這些任務。

💡 隊列 Queues
把時間消耗的任務推遲到稍後執行,從而提升應用的響應速度。例如,發送電子郵件可以在使用者提交表單後立即進行,而實際的發送過程則在背景進行。

✍🏻每日任務


使用 Laravel 的任務調度 Task Scheduling 和隊列 Queues 每天執行一次發送郵件。

參考文章:如何在laravel中使用调度队列发送电子邮件Laravel执行定时任务

step 1:建立一個 Laravel 專案
第 2 天:Laravel 啟服務與請求的生命週期有說明如果已經安裝 PHPComposer 和一個資料庫(如 MySQL)的條件下,可以省略直接進入安裝 Laravel 對應版本,所以這裡直接下指令件立一個新專案

composer create-project --prefer-dist laravel/laravel sent-email
cd sent-email
php artsian serve

step 2:配置 gmail 郵件

文件:发送邮件
郵件設置:如何在 .env 文件中配置郵件服務。
使用不同的郵件驅動:例如 SMTP、Mailgun、SendGrid 等。
發送郵件的不同方式:使用 Markdown、HTML 或純文本郵件。
郵件佇列:如何將郵件發送任務推送到隊列中以提升性能。

MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587

# 自己的 gmail,認證郵件服務器的帳戶,也就是用來登錄 gmail 的帳戶
MAIL_USERNAME=pol***bea***@gmail.com

# 自己的 gmail 密碼
MAIL_PASSWORD=***************
MAIL_ENCRYPTION=tls

# 發件人顯示的郵件地址,收件人可以看到郵件是從該地址發出的
MAIL_FROM_ADDRESS=pol***bea***@gmail.com

# 發件人名稱
MAIL_FROM_NAME="kuku"

step 3:建立 artisan 命令
下指令 php artisan make:command SendEmailapp/Console/Commands 中創建 SendEmail.php 的檔案,然後在 handle 方法增加發送郵件的邏輯

💡 這個命令通常是同步執行的,下指令 php artisan email:send pol***bea***@gmail.com 的時候,郵件將會立即發送

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;

class SendEmail extends Command
{
    /**
     * The name and signature of the console command.
     * 命令的簽名
     * 
     * @var string
     */
    protected $signature = 'email:send {email}';

    /**
     * The console command description.
     * 運行 php artisan list 或 php artisan help email:send 時會顯示這個描述
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Execute the console command.
     * 命令的執行邏輯,handle 方法會在命令被執行時自動調用
     */
    public function handle()
    {
        // 從命令的參數中獲取 email 值,這將是用戶在執行命令時傳遞的電子郵件地址
        $email = $this->argument('email');

        /**
         * 用 Mail Facade 的 raw 方法發送一封純文本郵件
         * 第一個參數是郵件內容
         * 第二個參數是一個回調函數,用於設置郵件的細節(如收件人和主題)
         */
        Mail::raw('This is a test email!', function ($message) use ($email) {
            $message->to($email)
                ->subject('Test Email');
        });

        // 命令執行完成後,使用 info 方法輸出一條成功信息,告訴用戶郵件已成功發送
        $this->info("成功發送信件給 {$email}");
    }
}

step 4:設定任務調度
打開 app/Console/Kernel.php,並在 schedule 方法中加入命令,這個命令將每天自動執行發送郵件

    /**
     * Define the application's command schedule.
     */
    protected function schedule(Schedule $schedule): void
    {
        // $schedule->command('inspire')->hourly();
        $schedule->command('email:send pol***bea***@gmail.com')->daily();
    }

step 5:建立隊列任務
指令 php artisan make:job SendEmailJob,並在 app/Jobs/SendEmailJob.php 寫發送郵件的邏輯

💡 這裡是一個作 job,跟 step 3 的命令不太一樣,任務推送到隊列時,實際的郵件發送是在後台進行的。

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;

/**
 * OOPs 的 Abstraction 抽象,這個類實現了 ShouldQueue 接口,表示這是一個隊列任務
 * 
 */
class SendEmailJob implements ShouldQueue
{
    /**
     * Dispatchable:允許這個任務被分派到隊列中
     * InteractsWithQueue:允許與隊列交互,例如檢查任務狀態
     * Queueable:允許使用者設置與隊列相關的選項
     */
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $email;

    /**
     * Create a new job instance.
     */
    public function __construct($email)
    {
        // 創建 SendEmailJob 實例時初始化 $email 屬性
        $this->email = $email;
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        Mail::raw('Queue 的隊列任務測試電子郵件!', function ($message) {
            $message->to($this->email)
                ->subject('Test Email from Queue');
        });
    }
}

step 6:在控制器中推送任務到隊列並且建立路由呼叫
下指令 php artisan make:controller EmailController 建立控制器

<?php

namespace App\Http\Controllers;

use App\Jobs\SendEmailJob;
use Illuminate\Http\Request;

class EmailController extends Controller
{
    public function sendEmail(Request $request)
    {
        $email = $request->input('email');
        SendEmailJob::dispatch($email);

        return response()->json(['message' => '電子郵件將很快發送!']);
    }
}
use App\Http\Controllers\EmailController;

Route::post('/send-email', [EmailController::class, 'sendEmail']);

step 7:運行隊列工作者
指令 php artisan queue:work

step 8:Test
用 postman 發送 POST 請求到 http://127.0.0.1:8000/api/send-email,並傳送一個 JSON 物件參數,包含 email 屬性

{
    "email": "123@test.com"
}

postman

💡 解決方法:
方法 1:如果遇到以上問題,可以嘗試降低自己的信箱安全性應用程式 (參考文章:Gmail用戶如何設定允許低安全性應用程式存取帳戶)
方法 2:Laravel 使用 Mailgun 發送Email


上一篇
第 15 天:中間件
下一篇
第 17 天:緩存 Cache
系列文
後端小白自學 Laravel30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言