MAXBY SSD 512GB/1TB M.2 NVMe PCIe Gen4x4 SSD NVMe Gen3/1TB PCIe 4.0 Garansi Resmi 5 Tahun Original

Laravel Scheduler dengan Cron: Konfigurasi yang Benar di Ubuntu

Apa Itu Laravel Scheduler dengan Cron?

Laravel Scheduler digunakan untuk menentukan kapan sebuah task harus dijalankan, sedangkan Cron di Ubuntu bertugas memanggil Laravel Scheduler secara berkala.

Sederhananya:

Ubuntu Cron
     ↓
schedule:run
     ↓
Laravel Scheduler
     ↓
Task

Misalnya kita mempunyai task:

Schedule::command('report:daily')
    ->dailyAt('08:00');

Cron tidak perlu mengetahui bahwa task tersebut harus dijalankan pukul 08:00.

Cron cukup menjalankan:

php artisan schedule:run

setiap menit.

Laravel kemudian memeriksa:

Apakah sekarang waktunya report:daily dijalankan?

Jika iya, Laravel menjalankan task tersebut.

Kenapa Cron Tetap Dijalankan Setiap Menit?

Ini merupakan konsep penting dalam Laravel Scheduler.

Misalnya kita memiliki:

Schedule::command('cleanup:data')
    ->dailyAt('02:00');

Cron tetap:

* * * * * ...

Artinya:

01:58 → schedule:run
01:59 → schedule:run
02:00 → schedule:run → cleanup:data
02:01 → schedule:run
02:02 → schedule:run

Pada pukul 02:00, Laravel melihat bahwa task sudah waktunya dijalankan.

Jadi:

Cron = pemicu

Laravel Scheduler = pengatur jadwal

Arsitektur Laravel Scheduler di Ubuntu

Pada server production, alurnya biasanya seperti ini:

Ubuntu VPS
   │
   ├── Cron
   │     ↓
   │  schedule:run
   │     ↓
   │  Laravel Scheduler
   │     ↓
   ├── Artisan Command
   ├── Job
   ├── Closure
   └── Task lainnya

Jika task menggunakan Queue:

Cron
 ↓
Laravel Scheduler
 ↓
Queue Job
 ↓
Redis
 ↓
Queue Worker
 ↓
Process Job

Jadi Scheduler dan Queue Worker memiliki tanggung jawab yang berbeda.

Sebelum Mengatur Cron

Pastikan project Laravel sudah dapat dijalankan secara normal.

Masuk ke directory project:

cd /var/www/example.com

Kemudian cek:

php artisan about

Jika Laravel dapat menampilkan informasi aplikasi, lanjutkan ke konfigurasi Scheduler.

Pastikan Artisan Bisa Berjalan

Tes:

php artisan --version

Misalnya:

Laravel Framework 12.x

Jika command ini gagal, jangan lanjut mengatur Cron terlebih dahulu.

Perbaiki masalah Laravel/PHP-nya.

Buat Task Scheduler

Sebagai contoh, kita membuat Command:

php artisan make:command CleanupTemporaryData

Kemudian:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class CleanupTemporaryData extends Command
{
    protected $signature = 'cleanup:temporary-data';

    protected $description = 'Membersihkan data sementara';

    public function handle()
    {
        $this->info('Cleanup selesai.');

        return self::SUCCESS;
    }
}

Tes secara manual:

php artisan cleanup:temporary-data

Jika berhasil, kita dapat memasukkannya ke Scheduler.

Menambahkan Task ke Scheduler

Pada versi Laravel yang menggunakan routes/console.php, misalnya:

use Illuminate\Support\Facades\Schedule;

Schedule::command('cleanup:temporary-data')
    ->dailyAt('02:00');

Untuk Laravel dengan struktur konfigurasi Scheduler yang berbeda, letakkan definisi schedule pada lokasi yang digunakan versi Laravel tersebut.

Yang penting adalah task terdaftar pada Laravel Scheduler.

Periksa Task dengan schedule:list

Jalankan:

php artisan schedule:list

Jika konfigurasi benar, task akan muncul.

Contoh:

0 2 * * *  cleanup:temporary-data

Jika task tidak muncul, masalahnya belum berada di Cron.

Periksa konfigurasi Scheduler terlebih dahulu.

Tes Scheduler Secara Manual

Jalankan:

php artisan schedule:run

Command ini meminta Laravel mengecek semua task yang seharusnya dijalankan pada saat tersebut.

Jika belum waktunya:

No scheduled commands are ready to run.

Jika task memang waktunya dijalankan, Laravel akan mengeksekusinya.

Gunakan schedule:work untuk Development

Untuk testing lokal, Anda dapat menjalankan:

php artisan schedule:work

Laravel akan menjalankan scheduler secara terus-menerus.

Contohnya:

schedule:work
      ↓
Menunggu
      ↓
Task waktunya tiba
      ↓
Task dijalankan
      ↓
Menunggu lagi

Namun untuk setup production berbasis Cron, biasanya kita menggunakan:

php artisan schedule:run

yang dipanggil Cron setiap menit.

Cek Cron di Ubuntu

Pastikan Cron terpasang:

sudo apt update

Kemudian:

sudo apt install cron

Pada Ubuntu, service Cron biasanya bernama:

cron

Cek statusnya:

sudo systemctl status cron

Jika normal:

Active: active (running)

Aktifkan Cron Saat Boot

Agar Cron otomatis aktif setelah server reboot:

sudo systemctl enable cron

Jika service belum berjalan:

sudo systemctl start cron

Kemudian cek kembali:

sudo systemctl status cron

Membuat Cron Job untuk Laravel

Edit Cron user:

crontab -e

Tambahkan:

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

Ganti:

/var/www/example.com

dengan lokasi project Laravel Anda.

Inilah konfigurasi paling umum untuk Laravel Scheduler di Ubuntu.

Penjelasan Cron Expression

Bagian:

* * * * *

berarti:

│ │ │ │ │
│ │ │ │ └── Hari dalam minggu
│ │ │ └──── Bulan
│ │ └────── Hari dalam bulan
│ └──────── Jam
└────────── Menit

Semua * berarti setiap nilai.

Jadi:

* * * * *

berarti:

Jalankan setiap menit.

Penjelasan Command Cron

Baris:

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

memiliki beberapa bagian.

cd /var/www/example.com

Masuk ke directory Laravel.

&&

Jalankan command berikutnya hanya jika cd berhasil.

php artisan schedule:run

Memanggil Laravel Scheduler.

>> /dev/null

Membuang output standar.

2>&1

Mengarahkan error ke output yang sama.

Gunakan Absolute Path PHP

Salah satu masalah Cron yang sering terjadi adalah:

php: command not found

Padahal saat menjalankan:

php -v

di terminal semuanya normal.

Hal ini dapat terjadi karena environment Cron berbeda dengan shell SSH.

Cari lokasi PHP:

which php

Misalnya hasil:

/usr/bin/php

Gunakan:

* * * * * cd /var/www/example.com && /usr/bin/php artisan schedule:run >> /dev/null 2>&1

Ini lebih aman untuk production.

Periksa Versi PHP

Jalankan:

php -v

Kemudian:

which php

Pastikan versi PHP sesuai dengan kebutuhan Laravel.

Misalnya aplikasi membutuhkan PHP 8.3, tetapi Cron menjalankan PHP 8.1, Scheduler dapat gagal walaupun aplikasi melalui browser terlihat normal.

Web PHP dan CLI PHP Bisa Berbeda

Pada server Laravel, terdapat kemungkinan:

Nginx
 ↓
PHP-FPM 8.3

sedangkan:

Cron
 ↓
PHP CLI 8.1

Akibatnya:

Website → Normal
Scheduler → Error

Karena Scheduler dijalankan melalui PHP CLI.

Pastikan PHP CLI yang digunakan Cron kompatibel dengan aplikasi.

Gunakan Path Laravel yang Absolut

Daripada:

* * * * * php artisan schedule:run

gunakan:

* * * * * cd /var/www/example.com && /usr/bin/php artisan schedule:run

Atau Anda dapat menggunakan path Artisan secara langsung:

* * * * * /usr/bin/php /var/www/example.com/artisan schedule:run

Format kedua lebih eksplisit dan tidak bergantung pada cd.

Contoh Cron yang Direkomendasikan

Untuk project:

/var/www/myapp

dan PHP:

/usr/bin/php

gunakan:

* * * * * /usr/bin/php /var/www/myapp/artisan schedule:run >> /dev/null 2>&1

Format ini sederhana dan mudah dipahami.

Jangan Membuat Cron untuk Setiap Task

Misalnya Anda memiliki:

cleanup
report
sync
notification
backup

Jangan membuat:

0 2 * * * cleanup
0 8 * * * report
*/10 * * * * sync
*/5 * * * * notification
0 3 * * * backup

Jika semuanya merupakan task Laravel, lebih baik:

* * * * * /usr/bin/php /var/www/myapp/artisan schedule:run

Kemudian jadwal dikelola di Laravel:

Schedule::command('cleanup')->dailyAt('02:00');

Schedule::command('report')->dailyAt('08:00');

Schedule::command('sync')->everyTenMinutes();

Schedule::command('notification')->everyFiveMinutes();

Dengan demikian konfigurasi jadwal terpusat di aplikasi.

Cek Cron yang Sudah Dibuat

Gunakan:

crontab -l

Pastikan muncul:

* * * * * /usr/bin/php /var/www/myapp/artisan schedule:run >> /dev/null 2>&1

Jika tidak muncul, Cron belum dikonfigurasi pada user tersebut.

Cron User vs Root

Perhatikan siapa yang membuat Cron.

Jika Anda menjalankan:

crontab -e

Cron tersebut berjalan sebagai user Anda.

Sedangkan:

sudo crontab -e

membuat Cron untuk root.

Ini penting karena user yang menjalankan Scheduler akan memengaruhi:

  • Permission
  • File yang dibuat
  • Log
  • Cache
  • Environment
  • Akses project

Sebaiknya Gunakan User Aplikasi

Misalnya aplikasi dijalankan oleh:

www-data

maka Anda dapat mempertimbangkan menjalankan Scheduler dengan user yang sesuai.

Namun jangan mengubah ownership atau user secara sembarangan.

Pastikan struktur permission aplikasi memang dirancang untuk user tersebut.

Masalah Permission pada Scheduler

Misalnya Scheduler menjalankan Command:

Storage::put('reports/daily.txt', $content);

Jika user Cron tidak memiliki permission ke:

storage/

task bisa gagal.

Periksa:

ls -la storage

dan:

ls -la bootstrap/cache

Laravel biasanya membutuhkan write access pada directory tersebut.

Jangan Menggunakan chmod -R 777

Jika menemukan:

Permission denied

hindari langsung:

chmod -R 777 /var/www/myapp

Solusi yang lebih baik adalah menentukan:

Siapa user aplikasi?
Siapa user Cron?
Directory mana yang perlu write?
Siapa owner-nya?

Kemudian atur permission secara spesifik.

Periksa Log Laravel

Jika Cron berhasil memanggil Scheduler tetapi task gagal, periksa:

tail -f /var/www/myapp/storage/logs/laravel.log

Misalnya muncul:

Permission denied

berarti task sebenarnya sudah dipanggil.

Masalahnya berada pada permission.

Jika:

RedisException

periksa Redis.

Jika:

Class not found

periksa dependency dan deployment.

Jangan Membuang Output Saat Debugging

Konfigurasi production sering menggunakan:

>> /dev/null 2>&1

Ini bagus untuk menghindari output yang tidak perlu.

Namun ketika debugging, lebih baik simpan output sementara.

Contoh:

* * * * * /usr/bin/php /var/www/myapp/artisan schedule:run >> /var/www/myapp/storage/logs/scheduler.log 2>&1

Kemudian:

tail -f /var/www/myapp/storage/logs/scheduler.log

Setelah masalah selesai, Anda dapat mengembalikan konfigurasi logging sesuai kebutuhan.

Cron Tidak Berjalan?

Jika Scheduler tidak berjalan otomatis, lakukan pengecekan dari bawah ke atas.

Cek Cron Service

sudo systemctl status cron

Cek Crontab

crontab -l

Cek PHP

which php
php -v

Cek Project

cd /var/www/myapp
php artisan --version

Cek Scheduler

php artisan schedule:list

Tes Manual

php artisan schedule:run

Jika semuanya berhasil secara manual tetapi tidak otomatis, fokus pada Cron.

Tes Cron dengan Command Sederhana

Jika masih tidak yakin Cron bekerja, buat Cron sederhana untuk menulis timestamp:

* * * * * date >> /tmp/cron-test.log

Tunggu beberapa menit, lalu:

cat /tmp/cron-test.log

Jika timestamp bertambah setiap menit:

Mon Aug 24 10:00:01 ...
Mon Aug 24 10:01:01 ...
Mon Aug 24 10:02:01 ...

berarti Cron berjalan.

Jika file tidak berubah, masalah berada pada Cron, bukan Laravel.

Tes Cron Langsung ke Laravel Log

Untuk debugging, Anda dapat menggunakan:

* * * * * /usr/bin/php /var/www/myapp/artisan schedule:run >> /tmp/laravel-scheduler.log 2>&1

Kemudian:

tail -f /tmp/laravel-scheduler.log

Ini membantu melihat apakah Laravel gagal dijalankan dari Cron.

Scheduler Tidak Menjalankan Task

Jika:

php artisan schedule:run

berhasil tetapi task tidak berjalan, periksa:

php artisan schedule:list

Misalnya task:

Schedule::command('report:daily')
    ->dailyAt('08:00');

tetapi saat ini pukul 10:00, tentu task tidak akan dijalankan.

Ini bukan error.

Laravel hanya menjalankan task ketika waktunya sesuai.

Timezone Sangat Penting

Misalnya Anda menginginkan:

08:00 WIB

tetapi Laravel menggunakan:

UTC

maka task dapat berjalan pada waktu yang berbeda dari yang diharapkan.

Periksa konfigurasi aplikasi.

Misalnya:

'timezone' => 'Asia/Jakarta',

Kemudian task:

Schedule::command('report:daily')
    ->dailyAt('08:00');

Jika aplikasi memang menggunakan waktu Indonesia, konfigurasi timezone harus konsisten.

Menentukan Timezone pada Task

Anda juga dapat menentukan timezone langsung pada task:

Schedule::command('report:daily')
    ->dailyAt('08:00')
    ->timezone('Asia/Jakarta');

Ini berguna ketika aplikasi membutuhkan jadwal berdasarkan timezone tertentu.

Periksa Waktu Server

Gunakan:

date

Untuk informasi timezone:

timedatectl

Contohnya:

Time zone: Asia/Jakarta (WIB, +0700)

Namun jangan hanya bergantung pada timezone server.

Periksa juga konfigurasi timezone Laravel.

Scheduler dan withoutOverlapping()

Task yang lama dapat bertabrakan dengan eksekusi berikutnya.

Contoh:

Schedule::command('report:generate')
    ->everyMinute()
    ->withoutOverlapping();

Jika task membutuhkan 3 menit:

00:00 → Task mulai
00:01 → Skip
00:02 → Skip
00:03 → Task selesai
00:03 → Task berikutnya dapat berjalan

Ini berguna untuk task yang tidak boleh berjalan bersamaan.

Task yang Menggunakan Queue

Jika Scheduler menjalankan Job:

Schedule::job(new GenerateReport)
    ->dailyAt('08:00');

maka Scheduler hanya memasukkan Job ke Queue.

Queue Worker tetap harus aktif.

Alurnya:

Cron
 ↓
Scheduler
 ↓
GenerateReport
 ↓
Redis
 ↓
Queue Worker

Jika Scheduler bekerja tetapi Worker mati:

Scheduler → berhasil
Queue → Job masuk
Worker → tidak ada

Job akan menumpuk.

Hubungan Cron dengan Supervisor

Cron dan Supervisor dapat digunakan bersamaan tetapi memiliki fungsi berbeda.

Cron:

Menjalankan Scheduler

Supervisor:

Menjaga Queue Worker tetap berjalan

Contoh:

Cron
 ↓
Laravel Scheduler
 ↓
Queue
 ↓
Supervisor
 ↓
Queue Worker

Jangan menggunakan Supervisor hanya karena aplikasi memiliki Scheduler.

Untuk Scheduler berbasis schedule:run, Cron sudah cukup pada banyak setup.

Cron vs Supervisor untuk Scheduler

Untuk Laravel Scheduler:

Cron
 ↓
schedule:run

adalah pendekatan sederhana dan umum.

Untuk Queue Worker:

Supervisor
 ↓
queue:work

lebih sesuai karena Worker adalah long-running process.

Sedangkan:

schedule:work

juga merupakan long-running process sehingga membutuhkan process manager jika digunakan sebagai mekanisme production.

Konfigurasi Production yang Disarankan

Misalnya project:

/var/www/myapp

PHP:

/usr/bin/php

Cron:

* * * * * /usr/bin/php /var/www/myapp/artisan schedule:run >> /dev/null 2>&1

Scheduler:

use Illuminate\Support\Facades\Schedule;

Schedule::command('cleanup:temporary-data')
    ->dailyAt('02:00')
    ->withoutOverlapping();

Schedule::command('report:daily')
    ->dailyAt('08:00');

Schedule::job(new SyncProducts)
    ->everyTenMinutes();

Queue Worker:

Supervisor
 ↓
php artisan queue:work redis

Arsitekturnya:

             Ubuntu VPS
                 │
        ┌────────┴────────┐
        ↓                 ↓
      Cron            Supervisor
        ↓                 ↓
 schedule:run       Queue Worker
        ↓                 ↓
 Laravel Scheduler     Redis
        │                 ↑
        └────── Job ──────┘

Setelah Mengubah .env

Scheduler dan Command dapat menggunakan konfigurasi yang sudah di-cache.

Setelah perubahan konfigurasi penting, Anda dapat menjalankan:

php artisan optimize:clear

Kemudian tes:

php artisan schedule:list

Jika menggunakan Queue Worker, restart Worker sesuai mekanisme deployment aplikasi.

Setelah Deployment

Queue Worker merupakan proses jangka panjang, sehingga perlu diperhatikan setelah deployment.

Untuk Queue Worker biasa:

php artisan queue:restart

Jika menggunakan Horizon:

php artisan horizon:terminate

Scheduler berbasis Cron tidak membutuhkan proses restart seperti Queue Worker karena Cron menjalankan schedule:run setiap menit.

Scheduler Tidak Perlu Dijalankan sebagai Daemon

Jika menggunakan Cron:

* * * * * /usr/bin/php /var/www/myapp/artisan schedule:run

Anda tidak perlu menjalankan:

php artisan schedule:work

secara bersamaan.

Pilih mekanisme yang sesuai.

Untuk setup Cron:

Cron → schedule:run

Untuk setup long-running:

Process Manager → schedule:work

Jangan menjalankan keduanya tanpa alasan karena dapat membuat Anda bingung ketika debugging.

Checklist Konfigurasi Laravel Scheduler + Cron

Sebelum menyimpulkan Scheduler rusak, periksa:

[ ] Laravel dapat menjalankan artisan
[ ] Task terdaftar
[ ] php artisan schedule:list berhasil
[ ] Task dapat dijalankan manual
[ ] Cron terinstall
[ ] Cron service aktif
[ ] crontab sudah dibuat
[ ] PHP path benar
[ ] Laravel path benar
[ ] User Cron memiliki permission
[ ] Timezone benar
[ ] Queue Worker aktif jika menggunakan Job
[ ] Redis aktif jika menggunakan Redis Queue
[ ] Log dapat diperiksa

Troubleshooting Berdasarkan Gejala

GejalaKemungkinan Penyebab
schedule:list kosongKonfigurasi Scheduler
schedule:run errorLaravel/PHP/configuration
Manual berhasil, Cron gagalCron environment/PHP path
Task berjalan di waktu salahTimezone
Task tidak munculScheduler belum terdaftar
Command gagalError pada Command
Job masuk Queue tapi tidak diprosesQueue Worker
php: command not foundPATH Cron
Permission deniedUser/permission
Cron tidak berjalan sama sekaliService/crontab
Task berjalan dua kaliMultiple server/overlap
Scheduler berhenti setelah deployEnvironment/configuration

Contoh Setup dari Nol

Misalnya Anda memiliki VPS Ubuntu dan project:

/var/www/blog

Pertama cek PHP:

which php

Misalnya:

/usr/bin/php

Tes Laravel:

cd /var/www/blog
/usr/bin/php artisan --version

Tes Scheduler:

/usr/bin/php artisan schedule:list

Kemudian edit Cron:

crontab -e

Tambahkan:

* * * * * /usr/bin/php /var/www/blog/artisan schedule:run >> /dev/null 2>&1

Simpan.

Cek:

crontab -l

Kemudian pastikan service:

sudo systemctl status cron

Jika semua benar, Cron akan memanggil Scheduler setiap menit.

Cara Memastikan Scheduler Benar-Benar Berjalan

Untuk debugging, ubah sementara Cron menjadi:

* * * * * /usr/bin/php /var/www/blog/artisan schedule:run >> /var/www/blog/storage/logs/scheduler.log 2>&1

Tunggu satu atau dua menit.

Kemudian:

tail -f /var/www/blog/storage/logs/scheduler.log

Jika tidak ada indikasi apa pun, tes:

/usr/bin/php /var/www/blog/artisan schedule:run

Jika manual berhasil tetapi Cron tidak, fokus pada:

Cron
User
PHP PATH
Permission
Environment

Kesimpulan

Konfigurasi Laravel Scheduler dengan Cron di Ubuntu sebenarnya cukup sederhana.

Konsep utamanya adalah:

Ubuntu Cron
     ↓
setiap menit
     ↓
php artisan schedule:run
     ↓
Laravel Scheduler
     ↓
Task yang waktunya sudah tiba

Konfigurasi Cron yang umum:

* * * * * /usr/bin/php /var/www/myapp/artisan schedule:run >> /dev/null 2>&1

Sementara jadwal task dikelola di Laravel:

Schedule::command('report:daily')
    ->dailyAt('08:00');

Untuk task yang membutuhkan Queue:

Schedule::job(new GenerateReport)
    ->dailyAt('08:00');

kemudian Queue Worker dipastikan tetap berjalan menggunakan process manager seperti Supervisor.

Jika Scheduler tidak berjalan, jangan langsung mengubah konfigurasi Laravel. Periksa secara berurutan:

Cron service
    ↓
crontab
    ↓
PHP path
    ↓
Laravel path
    ↓
schedule:list
    ↓
schedule:run
    ↓
Task
    ↓
Queue Worker jika diperlukan

Dengan pola tersebut, Laravel Scheduler dapat berjalan secara stabil di Ubuntu VPS dan seluruh jadwal aplikasi dapat dikelola dari satu tempat tanpa harus membuat Cron terpisah untuk setiap task.