Firebase Ngotot Tanpa Fitur Schedule di API: Trik Mengakalinya Pakai Laravel Queue

Firebase Ngotot Tanpa Fitur Schedule di API: Trik Mengakalinya Pakai Laravel Queue

Oleh Reggi, 29 Dec 2022

Pernah buka Firebase Console, klik menu Cloud Messaging, lalu takjub betapa gampangnya mengatur jam tayang push notification ke jutaan user? Semuanya tampak instan. Tapi rasa senang itu biasanya runtuh seketika saat kamu mulai buka IDE, bikin custom backend, dan menembak FCM via Postman atau API langsung. Parameter scheduling yang kamu cari ternyata nihil. Google sama sekali tidak menyediakan payload penjadwalan di level REST API-nya.

Kamu dipaksa memutar otak: apakah backend harus standby 24 jam penuh hanya untuk menahan request, atau ada cara yang jauh lebih elegan tanpa bikin server ngelag?

Jawabannya adalah mendistribusikan beban kerja tersebut ke sistem antrean. Mengakali limitasi API FCM bukan berarti harus membangun arsitektur rumit dari nol. Dengan ekosistem Laravel Queue, kamu bisa memarkir payload notifikasi dan mengeksekusinya tepat di waktu yang kamu mau, sembari menjaga response time server tetap instan.

Mengapa Harus Queue, Bukan Eksekusi Langsung?

Menembak HTTP request ke API pihak ketiga seperti Firebase membutuhkan waktu tunggu jaringan. Kalau controller kamu mengeksekusi cURL secara sinkron saat user menekan tombol di dashboard admin, web browser bakal tertahan (hanging) beberapa detik.

Laravel Queue memecah beban kerja ini menjadi background process. Begitu request masuk, server cuma butuh hitungan milidetik untuk memasukkan job ke antrean, lalu langsung melempar respons sukses ke pengguna. Laravel menyediakan beberapa pilihan backend antrean yang bisa dipilih sesuai kebutuhan:

Queue DriverKarakteristik Utama
databaseSimpel, tanpa setup server tambahan, ideal untuk skala awal hingga menengah.
RedisSuper cepat, berjalan in-memory, sangat efisien menangani throughput masif.
Amazon SQSFully managed message queuing service dari AWS, highly scalable.
BeanstalkdKhusus antrean kerja ringan dengan latensi rendah.

Untuk implementasi kali ini, kita gunakan driver database yang paling minim friksi karena tidak menuntut kamu memasang service tambahan seperti Redis di server lokal.

Setup Awal: Siapkan Jalur Database

Langkah paling dasar dimulai dari file environment. Buka .env di root project kamu, lalu arahkan driver antrean ke database.

env
APP_NAME=Laravel APP_ENV=local APP_KEY=base64:3k123123lm= APP_DEBUG=true APP_URL=http://localhost:8000 LOG_CHANNEL=stack LOG_LEVEL=debug DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=db DB_USERNAME=root DB_PASSWORD= BROADCAST_DRIVER=log CACHE_DRIVER=file FILESYSTEM_DRIVER=local QUEUE_CONNECTION=database SESSION_DRIVER=file SESSION_LIFETIME=120

Pastikan variabel QUEUE_CONNECTION sudah bernilai database. Setelah itu, Laravel butuh wadah fisik berupa tabel database untuk menampung antrean job yang belum matang. Jalankan generator migrasi tabel antrean dan eksekusi skemanya:

bash
php artisan queue:table php artisan migrate

Database kamu sekarang punya tabel baru bernama jobs yang siap diisi daftar tugas tertunda.

Membangun Logika Notifikasi di Dalam Job Class

Sekarang kita racik payload FCM di dalam dedicated Job. Buat filenya melalui terminal:

bash
php artisan make:job NotificationJob

Buka file app/Jobs/NotificationJob.php yang baru dibuat, lalu masukkan struktur kodenya seperti ini:

php
<?php namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; class NotificationJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $dongeng; public $tries = 3; /** * Create a new job instance. * * @return void */ public function __construct($dongeng) { $this->dongeng = $dongeng; } /** * Execute the job. * * @return void */ public function handle() { $url = 'https://fcm.googleapis.com/fcm/send'; /* API key diambil dari: Firebase Console -> Project Settings -> Cloud Messaging -> Server key */ $api_key = env('API_KEYFCM'); $fields = array( 'to' => "/topics/dongeng", 'collapse_key' => "type_a", 'notification' => array( "body" => "Body Desc", "title" => "Title Desc", "image" => "https://image.jpg" ), 'android' => array( "notification" => array( "image" => "https://image.jpg" ) ), 'data' => array( "body" => "Body Desc", "title" => "Title Desc", "link" => "https://image.jpg" ) ); $headers = array( 'Content-Type:application/json', 'Authorization:key=' . $api_key ); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields)); $result = curl_exec($ch); if ($result === FALSE) { die('FCM Send Error: ' . curl_error($ch)); } curl_close($ch); return $result; } public function failed() { // Logika fallback ketika job gagal dieksekusi setelah batas maksimal percobaan ($tries) } }

Variabel $dongeng di constructor bekerja sebagai penampung data entity dari controller. Properti $tries = 3 memberi jaminan jika request cURL ke Firebase mendadak gagal akibat masalah jaringan sesaat, antrean akan mencoba menembaknya ulang otomatis hingga tiga kali sebelum menyerah dan masuk ke method failed().

Meracik Controller untuk Menentukan Jadwal Tembak

Tahap penentu ada di Controller. Di sinilah kita mengukur jarak waktu antara sekarang dengan jam target pengiriman notifikasi.

Generate controllernya terlebih dahulu:

bash
php artisan make:controller NotificationController

Buka app/Http/Controllers/NotificationController.php dan susun fungsinya:

php
public function sendnotification(Request $request) { $dongeng = Post::find($request->id); // Hitung selisih waktu dari sekarang menuju jam 17:00:00 hari ini dalam satuan menit $delay = Carbon::parse()->floatDiffInMinutes('17:00:00'); // Masukkan job ke antrean database dengan jeda waktu delay dispatch(new NotificationJob($dongeng))->delay(now()->addMinutes($delay)); return redirect()->route('posts.index') ->with('success', 'Notification Dongeng ' . $dongeng->title . ' will send in ' . ($delay / 60) . ' hours'); }

Metode Carbon::parse()->floatDiffInMinutes('17:00:00') menghitung durasi mundur menuju jam target secara dinamis. Angka menit ini kemudian dioper ke method chained ->delay(now()->addMinutes($delay)).

Job tersebut tidak akan langsung disambar oleh worker, melainkan diparkir manis di tabel jobs sampai waktu rilisnya tiba. Kamu bebas memodifikasi satuan waktu ini sesuai kebutuhan campaign marketing di backend, baik itu hitungan menit, jam, maupun hari.

Dengan trik arsitektur sederhana ini, ketiadaan parameter jadwal di API FCM bukan lagi masalah buntu. Server kamu tetap enteng, UI dashboard admin responsif tanpa loading lama, dan notifikasi meluncur tepat waktu ke layar pengguna.


Sedang Ramai Dibaca