Definisi task baru lengkap setelah frekuensinya ditentukan: seberapa sering dan pada jam berapa task harus berjalan. Scheduler Laravel menyediakan puluhan method frekuensi yang pada akhirnya dikompilasi menjadi satu ekspresi cron lima field — jadi memahami frekuensi berarti memahami bagaimana method-method tersebut menulis cron untuk kita. Pada chapter ini kita petakan method yang tersedia, bereksperimen dengan schedule:list sebagai alat verifikasi, lalu tutup dengan constraint kondisional dan urusan yang sering bikin terpeleset: zona waktu.
Method Frekuensi Inti #
Berikut pemetaan method frekuensi yang paling sering dipakai beserta ekspresi cron yang dihasilkannya:
| Method | Ekspresi cron | Berarti |
|---|---|---|
everySecond() | * * * * * | setiap detik (sub-menit) |
everyMinute() | * * * * * | setiap menit |
everyFiveMinutes() | */5 * * * * | tiap 5 menit |
hourly() | 0 * * * * | tiap jam tepat |
hourlyAt(17) | 17 * * * * | menit ke-17 tiap jam |
daily() / dailyAt('2:30') | 0 0 * * * / 30 2 * * * | tengah malam / jam tertentu |
twiceDaily(8, 14) | 0 8,14 * * * | dua kali sehari |
weekly() / weeklyOn(1, '8:00') | 0 0 * * 0 / 0 8 * * 1 | mingguan / Senin jam 08:00 |
monthly() / monthlyOn(1, '0:00') | 0 0 1 * * | tanggal 1 tiap bulan |
quarterly() | 0 0 1 1-12/3 * | awal kuartal |
yearly() | 0 0 1 1 * | sekali setahun |
Method jam (at('08:00'), dailyAt(), weeklyOn()) menerima format HH:MM atau H:MM. Method menit (hourlyAt()) juga menerima array, misalnya hourlyAt([10, 30, 50]) menghasilkan 10,30,50 * * * *.
Keluarga jam yang lebih jarang dipakai mengikuti pola yang sama dan semuanya menerima offset: everyTwoHours(30) berarti menit ke-30 setiap dua jam, lalu everyThreeHours(), everyFourHours(), dan everySixHours() mengikuti. Untuk kasus yang tidak tercakup method mana pun, method cron() menerima ekspresi mentah — cron('15 10 * * 1-5') menulis field lima langsung tanpa perantara. Prinsip pemilihannya sederhana: pakai method bernama bila tersedia agar jadwal terbaca sebagai niat, simpan cron() untuk pola yang benar-benar khusus.
Eksperimen: Sebelas Jadwal Sekaligus #
Cara tercepat memahami komposisi frekuensi adalah melihat langsung hasil kompilasinya. Kita definisikan sebelas task di routes/console.php — sengaja memakai command yang sama agar fokus jatuh pada pola cronnya:
Schedule::call(fn () => null)->everyMinute()->name('ping-healthcheck');
Schedule::command('tasks:prune')->everyFiveMinutes();
Schedule::command('tasks:prune')->hourlyAt(17);
Schedule::command('tasks:prune')->dailyAt('02:30');
Schedule::command('tasks:prune')->twiceDaily(8, 14);
Schedule::command('tasks:prune')->weekdays()->at('08:00');
Schedule::job(new SendDailyReport)->weeklyOn(1, '03:00');
Schedule::command('report:generate')->monthlyOn(1, '00:00');
Schedule::command('report:generate')->quarterly();
Schedule::command('report:generate')->yearly();
Schedule::command('report:generate')->dailyAt('06:00')->timezone('Asia/Jakarta');Output yang Dihasilkan (schedule:list):
* * * * * ping-healthcheck ........ Next Due: 1 minute from now
*/5 * * * * php artisan tasks:prune Next Due: 5 minutes from now
17 * * * * php artisan tasks:prune Next Due: 47 minutes from now
30 2 * * * php artisan tasks:prune .. Next Due: 6 hours from now
0 8,14 * * * php artisan tasks:prune . Next Due: 11 hours from now
0 8 * * 1-5 php artisan tasks:prune . Next Due: 11 hours from now
0 3 * * 1 App\Jobs\SendDailyReport .. Next Due: 5 days from now
0 0 1 * * php artisan report:generate Next Due: 2 weeks from now
0 0 1 1-12/3 * php artisan report:generate Next Due: 2 months from now
0 0 1 1 * php artisan report:generate Next Due: 2 months from now
0 23 * * * php artisan report:generate Next Due: 2 hours from nowPerhatikan dua hal dari listing di atas. Pertama, weekdays()->at('08:00') menyusun dua field sekaligus: field jam 8 dan field hari 1-5 (Senin sampai Jumat). Kedua, baris terakhir tampil sebagai 0 23 * * * padahal kodenya dailyAt('06:00') — itu efek ->timezone('Asia/Jakarta') yang akan kita bedah di subbab terakhir.
Constraint Tambahan #
Selain pola cron, scheduler menyediakan constraint yang dievaluasi saat runtime. Yang paling sering dipakai:
weekdays()— membatasi Senin–Jumat (mengubah field hari pada cron).between('09:00', '17:00')— hanya berjalan pada rentang jam tertentu.when(closure)/skip(closure)— kondisi bebas yang mengembalikan boolean.
Berikut demonstrasi nyata keduanya. Sandbox mendefinisikan dua task everyMinute — satu dengan between(), satu dengan when() — lalu schedule:run dieksekusi pada pukul 20:25:
Schedule::command('tasks:prune')
->everyMinute()
->between('09:00', '17:00')
->name('prune-jam-kerja');
Schedule::command('tasks:prune')
->everyMinute()
->when(fn () => date('N') < 6)
->name('prune-hari-kerja');Output yang Dihasilkan:
2026-10-13 20:25:21 Running ['artisan' tasks:prune] .......... 217.40ms DONE
⇂ prune-hari-kerja Hanya prune-hari-kerja yang tampil. Task prune-jam-kerja lolos uji cron * * * * * tetapi ditolak constraint between('09:00', '17:00') karena pukul 20:25 berada di luar jam kerja — dan 13 Oktober 2026 adalah hari Selasa (date('N') === 2), sehingga closure when() mengembalikan true. Constraint gagal berarti task dilewati tanpa error; pengecekan terjadi di filtersPass() sebelum eksekusi.
Zona Waktu: Cron Server vs Aplikasi #
Kronologi menentukan kapan schedule:run dipanggil ada di tangan cron daemon yang mengikuti jam server. Namun penentuan task mana yang due dievaluasi scheduler berdasarkan zona waktu aplikasi — nilai timezone di config/app.php, yang defaultnya UTC.
Method ->timezone() mengubah evaluasi per-task. Jadwal dailyAt('06:00')->timezone('Asia/Jakarta') pada eksperimen kita berarti pukul 06:00 WIB — scheduler mengeksekusinya saat jam UTC menunjukkan 23:00. Perintah schedule:list --timezone=Asia/Jakarta memperlihatkan seluruh jadwal dalam tampilan WIB:
30 9 * * * php artisan tasks:prune . Next Due: 6 hours from now
0 15,21 * * * php artisan tasks:prune Next Due: 11 hours from now
0 15 * * 1-5 php artisan tasks:prune . Next Due: 11 hours from now
0 10 * * 1 App\Jobs\SendDailyReport . Next Due: 5 days from now
0 6 * * * php artisan report:generate Next Due: 2 hours from nowTask 30 2 * * * (02:30 UTC) kini tampil sebagai 30 9 * * * (09:30 WIB), sementara task ber-timezone Jakarta tetap tampil 0 6 * * * karena memang didefinisikan dalam WIB.
Frekuensi dan constraint mengatur kapan task berjalan; dua chapter ke depan mengatur bagaimana task berjalan. Yang pertama: mencegah eksekusi tumpang tindih ketika task berjalan lebih lama dari intervalnya di Preventing Overlapping . Rujukan method frekuensi lengkap ada di dokumentasi Task Scheduling .