Laravel: Belajar Laravel Queue
Ketika mengembangkan sebuah website mungkin kita akan punya satu atau dua proses yang akan memakan waktu yang lama untuk dieksekusi. Dengan Laravel Queue kita bisa mengirim proses ini untuk dijalankan dibelakang layar (background). Konfigurasi untuk Laravel Queue berada di berkas config/queue.php
. Pada file ini, terdapat konfigurasi untuk koneksi yang digunakan, driver yang dipakai, dan dimana pesan error akan disimpan.
Connection dan Queues
Sebelum jauh penjelasan tentang queue, ada baiknya kita pahami perbedaan antara koneksi dengan queues. Pada berkas config/queue.php
terdapat konfigurasi untuk untuk connections
....
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
'after_commit' => false,
],
'beanstalkd' => [
'driver' => 'beanstalkd',
'host' => 'localhost',
'queue' => 'default',
'retry_after' => 90,
'block_for' => 0,
'after_commit' => false,
],
'sqs' => [
'driver' => 'sqs',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'queue' => env('SQS_QUEUE', 'default'),
'suffix' => env('SQS_SUFFIX'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'after_commit' => false,
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
'after_commit' => false,
],
],
...
Konfigurasi ini merupakan konfigurasi untuk mengkoneksikan Laravel Queue dengan backend queue services (yang akan menjalankan queue) seperti Amazon SQS, Redis, atau Beanstalk. Masing-masing konfigurasi koneksi ini bisa mempunyai lebih dari satu proses queue.
Diberkas config/queue.php
juga, kita melihat setiap koneksi queue mempunyai attribut queue
. Attribut ini merupakan queue service default yang akan digunakan ketika kita tidak memberitahukan Laravel Queue service queue mana yang kita gunakan
use App\Jobs\AcceptAllRegistration;
// This job is sent to the default connection's default queue...
AcceptAllRegistration::dispatch();
// This job is sent to the default connection's "emails" queue...
AcceptAllRegistration::dispatch()->onQueue('emails');
Cara paling mudah untuk menjalankan queue adalah dengan menggunakan driver database karena kita tidak perlu konfigurasi tambahan atau package tambahan. Untuk menggunakan driver database pada queue bisa menggunakan artisan dengan perintah
php artisan queue:table
Pastikan koneksi kedatabase sudah sesuai dengan yang digunakan. Perintah tersebut akan membuat sebuah berkas migrasi baru untuk membuat tabel jobs
yang akan menjadi tempat untuk menyimpan job yang dijalankan.
Job adalah proses yang queue jalankan
Kemudian jalankan perintah
php artisan migrate
untuk memigrasi table jobs yang sudah digenerate oleh Laravel Queue.
Terakhir, ubah nilai dari variabel QUEUE_CONNECTION
di berkas .env
menjadi database
QUEUE_CONNECTION=database
Membuat Job
Job bisa dibuat dengan perintah artisan
php artisan make:job AcceptAllRegistration
Katakanlah kita punya sebuah sistem dimana setiap pengguna yang mendaftar harus di accept secara manual
Perintah artisan sebelumnya akan membuat sebuah class baru di app/Jobs/
dengan nama AcceptAllRegistration.php
. Kelas ini hanya mempunyai satu fungsi utama, fungsi handle()
dan fungsi constructor. Semua process queue job biasanya kita tulis di fungsi handle()
dan fungsi __construct()
biasanya kita gunakan untuk menyiapkan data yang akan diproses oleh job.
Persiapan Data
Kita akan menambahkan satu kolom baru ditabel users
yaitu kolom dengan nama is_active
untuk menandakan bahwa pengguna yang mendaftar sudah diterima atau belum. Kolom is active akan bertype tiny integer dengan constraint nya 1, kolom ini hanya akan menyimpan data 0 atau 1, 0 kalau pendaftarannya belum diterima dan 1 satu kalau pendaftarannya sudah diterima.
Membuat migration untuk menambahkan kolo, baru ke tabel users
php artisan make:migration add_column_to_users_table --table=users
Kemudian buka file migration yang baru dibuat dan tambah kolom baru
...
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->tinyInteger('is_active');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('is_active');
});
}
...
dan jangan lupa untuk menambahkan kolom baru ke model User
...
protected $fillable = [
'name',
'email',
'password',
'is_active'
];
...
terkahir jalan migrasi untuk menambahkan kolom, didatabase
php artisan migrate
Menambahkan data dummy
Data dummy bisa ditambahkan manual atau bisa menggunakan faker, contoh selanjutnya adalah menggunakan faker
// file: database/factories/UserFactory.php
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
'is_active' => 0,
];
}
/**
* Indicate that the model's email address should be unverified.
*
* @return static
*/
public function unverified()
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}
// file: database/seeders/DatabaseSeeder.php
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
\App\Models\User::factory(10000)->create();
}
}
php artisan migrate:fresh --seed
Jika tahapan diatas berhasil diajalankan maka sekarang kita sudah punya 10000 user yang belum diterima pendaftarannya.
Menajalankan Job
Jadi, proses job yang kita buat ini adalah proses untuk mengubah angka 0 menjadi 1 di kolom is_active
pada tabel users
. Jika kita menjalankan proses ini melalui request browser biasa tentu hal ini akan membuat loading atau response dari server menjadi lama karena ada proses yang besar dijalankan. Disinilah queue berperan penting, kita bisa menjalankan proses update ini secara asyncronous (belakang layar) dengan membuat satu job khusus untuk proses pengupdatenya.
Pada fungsi handle()
di job AcceptAllRegistration
kita akan menambahkan kode
...
$users = \App\Models\User::all();
foreach ($users as $user) {
if ((int)$user->is_active !== 1) {
\App\Models\User::find($user->id)->update([
'is_active' => 1
]);
}
}
...
Untuk menjalankan job kita akan memanfaatkan clousure function di routing, walaupun cara terbaiknya adalah menulis di controller
// file: routes/web.php
...
Route::get('/', function () {
\App\Jobs\AcceptAllRegistration::dispatch();
echo "success";
});
..
Jika sudah keluar tulisan success
di browser kita bisa menjalan worker untuk mengeksekusi job
php artisan queue:work