โ† Semua pembelajaran / Laravel Nol โ†’ Enterprise
Fase 3 ยท Arsitektur Laravel

Penjadwalan tugas

Penjadwalan Laravel menaruh semua tugas berkala di dalam kode yang ter-review. Yang berubah saat aplikasi naik skala: kamu harus memastikan hanya satu server yang benar-benar menjalankannya.

Sumber asli laravel.com Resmi Rangkuman ~5 menit baca

Intisari

  • Jadwal ditulis di routes/console.php, dijalankan oleh satu entri cron per menit.
  • ->onOneServer() wajib begitu ada lebih dari satu instance โ€” kalau tidak, tugas berjalan berkali-kali.
  • ->withoutOverlapping() mencegah tugas lambat menumpuk di atas dirinya sendiri.
  • Tugas berat sebaiknya cuma mengantre job, bukan mengerjakannya di proses penjadwal.
  • Di ECS, entri cron digantikan EventBridge Scheduler atau satu task khusus โ€” dibahas di Fase 9.

Mendefinisikan jadwal

// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('keranjang:bersihkan --hari=7')
    ->dailyAt('03:00')
    ->timezone('Asia/Jakarta')
    ->onOneServer()
    ->withoutOverlapping()
    ->runInBackground();

Schedule::job(new SinkronKatalog)->hourly();

Schedule::call(fn () => Cache::forget('statistik'))->everyThirtyMinutes();

Schedule::command('laporan:bulanan')
    ->monthlyOn(1, '06:00')
    ->emailOutputOnFailure('[email protected]');
php artisan schedule:list      # lihat semuanya beserta waktu jalan berikutnya
php artisan schedule:run       # jalankan yang jatuh tempo sekarang
php artisan schedule:test      # jalankan satu tugas secara manual

Satu entri cron untuk semuanya

* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1

Cron menjalankan schedule:run setiap menit; Laravel yang memutuskan tugas mana yang jatuh tempo. Keuntungannya besar: menambah jadwal baru adalah perubahan kode yang ter-review, bukan perubahan crontab di server yang tidak ada riwayatnya.

Dua pengaman yang berbeda

MethodMencegahButuh
onOneServer()Tugas yang sama berjalan di beberapa server sekaligusCache bersama (Redis / DynamoDB)
withoutOverlapping()Tugas berjalan lagi padahal yang sebelumnya belum selesaiCache bersama

Ini kesalahan produksi yang khas. Aplikasi berjalan di tiga kontainer; ketiganya menjalankan schedule:run; email ringkasan harian terkirim tiga kali. onOneServer() memakai kunci di cache bersama supaya hanya satu yang menang. Syaratnya: driver cache-nya harus bersama โ€” file atau array tidak akan menolong karena setiap kontainer punya salinannya sendiri.

Jangan bekerja di dalam penjadwal

// KURANG BAIK โ€” proses penjadwal menahan pekerjaan panjang
Schedule::call(function () {
    foreach (Pengguna::all() as $u) {
        (new BuatLaporan)->untuk($u);          // 20 menit di satu proses
    }
})->daily();

// LEBIH BAIK โ€” penjadwal cuma mengantre; worker yang bekerja, dan bisa diskalakan
Schedule::call(function () {
    Pengguna::query()->select('id')->chunkById(500, function ($batch) {
        BuatLaporan::dispatch($batch->pluck('id')->all());
    });
})->dailyAt('02:00');

Alasannya bukan kerapian: proses penjadwal yang berjalan 20 menit akan bertabrakan dengan jadwal berikutnya, tidak punya mekanisme percobaan ulang, dan tidak terlihat di dasbor antrean mana pun.

Menghindari beban serentak

Schedule::command('laporan:harian')->dailyAt('03:00');
Schedule::command('arsip:bersihkan')->dailyAt('03:07');   // digeser, bukan ditumpuk
Schedule::command('indeks:bangun')->dailyAt('03:15');

Menjadwalkan sepuluh tugas pada pukul 03:00 berarti sepuluh proses PHP menyala serentak dan sepuluh gelombang query mengenai database bersamaan. Menggeser beberapa menit tidak mengubah apa pun bagi bisnis, tapi mengubah banyak hal bagi database.

Di lingkungan container

Kontainer aplikasi biasanya tidak menjalankan cron. Ada dua pola yang lazim di AWS, dan keduanya dibahas di Fase 9:

PolaCara kerjaCatatan
Task penjadwal khususSatu ECS service berisi satu task yang menjalankan schedule:workSederhana; tetap pasang onOneServer() saat deploy berlangsung
EventBridge SchedulerEventBridge menjalankan task ECS sekali per menitTidak ada proses menganggur, tapi ada biaya start task

Perhatikan zona waktu. Kontainer hampir selalu berjalan dalam UTC. dailyAt('03:00') berarti pukul 3 pagi UTC โ€” pukul 10 pagi WIB. Sebutkan ->timezone('Asia/Jakarta') secara eksplisit untuk setiap jadwal yang dipahami manusia sebagai jam kerja.

Latihan: jadwalkan perintah toko:ringkasan dari Fase 0 supaya berjalan tiap lima menit dengan withoutOverlapping(), jalankan php artisan schedule:list dan pastikan waktu berikutnya sesuai zona waktumu. Lalu buat perintah itu sleep(400) dan buktikan bahwa jalannya yang kedua benar-benar dilewati.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.