12/08/2018, 15:00

Laravel: Task Scheduling

Hôm nay mình sẽ giới thiệu cho các bạn về 1 tính năng khá hay của Laravel. Đó là Task Scheduling (Lập lịch làm việc) ### **Introduction** Trước đây, có thể bạn đã từng tạo một Cron cho một tác vụ nào đó mà bạn muốn lập lịch để chạy trên server của bạn. Tuy nhiên, sẽ khá phiền phức nếu bạn ...

Hôm nay mình sẽ giới thiệu cho các bạn về 1 tính năng khá hay của Laravel. Đó là Task Scheduling (Lập lịch làm việc)


### **Introduction**
Trước đây, có thể bạn đã từng tạo một Cron cho một tác vụ nào đó mà bạn muốn lập lịch để chạy trên server của bạn. Tuy nhiên, sẽ khá phiền phức nếu bạn muốn thay đổi hoặc thêm các schedules mới khi bạn phải SSH đến server của bạn để thực hiện việc này.

Lệnh scheduler của Laravel cho phép bạn xác định lịch trình của mình một cách dễ dàng ngay trong chính Laravel. Khi sử dụng scheduler, bạn chỉ cần duy nhất một Cron entry trên server của bạn. Lịch trình làm việc của bạn sẽ được định nghĩa trong phương thức schedule trên file app/Console/Kernel.php. Để giúp bạn bắt đầu, một ví dụ đơn giản được định nghĩa trong phương thức:


**Starting The Scheduler**

Khi sử dụng scheduler, bạn chỉ cần thêm 1 mục Cron sau vào server của bạn. Nếu bạn không biết làm thế nào để thêm các mục Cron vào server của mình, hãy xem xét sử dụng 1 service như Laravel Forge mà có thể quản lý các mục Cron cho bạn:

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

Cron này sẽ gọi lệnh Laravel scheduler mỗi phút. Khi lệnh schedule:run được thực thi, Laravel sẽ tìm biểu thức scheduled task của bạn và chạy các task đến kỳ hạn.


### **Defining Schedules**
Bạn có thể định nghĩa tất cả các scheduled task trong phương thức ```schedule``` của lớp ```AppConsoleKernel```. Để bắt đầu, hãy xem ví dụ về lập lịch 1 task. Trong ví dụ này, chúng ta sẽ lạp 1 ```Closure``` để được gọi mỗi ngày vào lúc nửa đêm. Trong ```Closure```, chúng ta sẽ thực hiện một truy vấn cơ sở dữ liệu để xóa bảng: ``` <?php

namespace AppConsole;

use DB; use IlluminateConsoleSchedulingSchedule; use IlluminateFoundationConsoleKernel as ConsoleKernel;

class Kernel extends ConsoleKernel { /** * The Artisan commands provided by your application. * * @var array */ protected $$ommands = [ AppConsoleCommandsInspire::class, ];

/**
 * Define the application's command schedule.
 *
 * @param  IlluminateConsoleSchedulingSchedule  $schedule
 * @return void
 */
protected function schedule(Schedule $schedule)
{
    $schedule->call(function () {
        DB::table('recent_users')->delete();
    })->daily();
}

}

Ngoài việc lên kế hoạch cho ```Closure```, bạn cũng có thể lập lịch các lên ```Artisan``` và các lệnh hệ điều hành. Ví dụ, bạn có thể sử dụng phương thức ```command``` để lập lịch cho 1 ```Artisan``` command sử dụng tên command hoặc class:

$$chedule->command('emails:send --force')->daily();

$$chedule->command(EmailsCommand::class, ['--force'])->daily();

Lệnh ```exec``` có thể ddwwocj sử dụng để đưa ra các lệnh cho hệ điều hành:

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

<br>
**Schedule Frequency Options**

Dĩ nhiên, có nhiều lựa chọn về thời gian để bạn có thể  lập lịch cho task của mình:
![](https://viblo.asia/uploads/9503fd4a-eb68-4810-92a1-82c3673a955b.png)

Những phương thức này có thể được kết hợp với các ràng buộc bổ sung để tạo ra các lịch trình tinh vi hơn nữa mà chỉ chạy trong những ngày nhất định trong tuần. Ví dụ: để lập lịch một lệnh để chạy hàng tuần vào thứ hai:

// Run once per week on Monday at 1 PM... $$chedule->call(function () { // })->weekly()->mondays()->at('13:00');

// Run hourly from 8 AM to 5 PM on weekdays... $$chedule->command('foo') ->weekdays() ->hourly() ->timezone('America/Chicago') ->between('8:00', '17:00');

Dưới đây là danh sách các ràng buộc thời gian bổ sung:
![](https://viblo.asia/uploads/30052178-8fa1-4b68-ad1d-ff6d72589934.png)

_**Between Time Constraints**_

Phương thức ```between``` có thể được sử dụng để hạn chế việc thực hiện một task dựa trên khoảng thời gian trong ngày:

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

Tương tự, phương thức ```exceptBetween``` được sử dụng để loại trừ việc thực hiện một task trong một khoảng thời gian:

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

<br>
**Preventing Task Overlaps**

<br>
Theo mặc định, các task scheduled sẽ được chạy ngay cả khi instance trước đó của task vẫn đang chạy. Để ngăn chặn điều này, bạn có thể sử dụng phương thức ```withoutOverLapping```

$$chedule->command('emails:send')->withoutOverlapping();

Trong ví dụ này, câu lệnh Artisan ```emails:send``` sẽ được chạy mỗi phút nếu nó chưa chạy. Phương pháp ```withoutOverLapping``` đặc biệt hữu ích nếu bạn các task thay đổi đáng kể trong thời gian thực hiện của chúng, ngăn không cho bạn dự đoán chính xác thời gian của một task nhất định sẽ mất.

<br>
**Maintenance Mode**

<br>
scheduled task của Laravel sẽ không chạy khi Laravel đang ở [chế độ bảo trì ](https://laravel.com/docs/5.4/configuration#maintenance-mode)vì họ không muốn công việc của bạn can thiệp vào bất kỳ bảo trì chưa hoàn thành nào bạn có thể thực hiện trên server của bạn, Tuy nhiên, nếu bạn muốn buộc một task chạy ngay cả trong chế độ bảo trì, bạn có thể sử dụng phương thức ```evenInMaintenanceMode```:

$$chedule->command('emails:send')->evenInMaintenanceMode();

<br>

### **Task Output**

<br>
Laravel scheduler cung cấp một số phương thức thuận tiện để làm việc với output được tạo ra bởi các scheduled task. Đầu tiên, bằng cách sử dụng phương thức ```sendOutputTo```, bạn có thể gửi output tới một file để kiểm duyệt sau:

schedule−>command(′emails:send′)−>daily()−>sendOutputTo(schedule->command('emails:send') ->daily() ->sendOutputTo(schedule>command(emails:send)>daily()>sendOutputTo(filePath);

Nếu bạn muốn nối output vào 1 file nhất định, bạn có thể sử dụng phương thức ```appendOutputTo```:

schedule−>command(′emails:send′)−>daily()−>appendOutputTo(schedule->command('emails:send') ->daily() ->appendOutputTo(schedule>command(emails:send)>daily()>appendOutputTo(filePath);

Sử dụng phương thức ```emailOutputTo```, bạn có thể gửi email output đến 1 địa chỉ email bạn chọn. Trước khi gửi email output của một task, bạn nên cấu hình các [email service](https://laravel.com/docs/5.4/mail) của Laravel:

schedule−>command(′foo′)−>daily()−>sendOutputTo(schedule->command('foo') ->daily() ->sendOutputTo(schedule>command(foo)>daily()>sendOutputTo(filePath) ->emailOutputTo('foo@example.com');

<br>
### **Task Hooks**

<br>
Sử dụng phương thức ```before``` và ```after```, bạn có thể chỉ định mã được thực hiện trước và sau khi công việc đã được lập lịch hoàn tất.

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

Hy vọng bài dịch của mình sẽ hữu ích với các bạn :D
0