Solusi 1:
Cara memperbaiki semua kesengsaraan/masalah terkait crontab Anda (Linux)
Ini adalah wiki komunitas, jika Anda melihat sesuatu yang salah dengan jawaban ini atau memiliki informasi tambahan, silakan edit.
Pertama, terminologi dasar:
- cron(8) adalah daemon yang menjalankan perintah terjadwal.
- crontab(1) adalah program yang digunakan untuk memodifikasi file crontab(5) pengguna.
- crontab(5) adalah file per pengguna yang berisi instruksi untuk cron(8).
Berikutnya, edukasi tentang cron:
Setiap pengguna di sistem mungkin memiliki file crontab mereka sendiri. Lokasi file root dan crontab pengguna bergantung pada sistem tetapi umumnya di bawah /var/spool/cron
.
Ada /etc/crontab
di seluruh sistem file, /etc/cron.d
direktori mungkin berisi fragmen crontab yang juga dibaca dan ditindaklanjuti oleh cron. Beberapa distribusi Linux (misalnya, Red Hat) juga memiliki /etc/cron.{hourly,daily,weekly,monthly}
yang merupakan direktori, skrip di dalamnya yang akan dieksekusi setiap jam/hari/minggu/bulan, dengan hak akses root.
root selalu dapat menggunakan perintah crontab; pengguna biasa mungkin atau mungkin tidak diberikan akses. Saat Anda mengedit file crontab dengan perintah crontab -e
dan simpan, crond memeriksanya untuk validitas dasar tetapi tidak menjamin file crontab Anda terbentuk dengan benar. Ada file bernama cron.deny
yang akan menentukan pengguna mana yang tidak dapat menggunakan cron. cron.deny
lokasi file bergantung pada sistem dan dapat dihapus yang memungkinkan semua pengguna menggunakan cron.
Jika komputer tidak dihidupkan atau daemon crond tidak berjalan, dan tanggal/waktu untuk menjalankan perintah telah berlalu, crond tidak akan mengejar dan menjalankan kueri sebelumnya.
rincian crontab, cara merumuskan perintah:
Perintah crontab diwakili oleh satu baris. Anda tidak dapat menggunakan \
untuk memperluas perintah melalui beberapa baris. Hash (#
) tanda mewakili komentar yang berarti apa pun di baris itu diabaikan oleh cron. Spasi kosong dan baris kosong di awal diabaikan.
Berhati-hatilah saat menggunakan persen (%
) masuk perintah Anda. Kecuali mereka lolos \%
mereka diubah menjadi baris baru dan semuanya setelah %
pertama yang tidak lolos diteruskan ke perintah Anda di stdin.
Ada dua format untuk file crontab:
-
Crontab pengguna
# Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) # | | | | | # * * * * * command to be executed
-
Lebar sistem
/etc/crontab
dan/etc/cron.d
fragmen# Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) # | | | | | # * * * * * user-name command to be executed
Perhatikan bahwa yang terakhir membutuhkan nama pengguna. Perintah akan dijalankan sebagai pengguna bernama.
5 bidang pertama baris menunjukkan waktu saat perintah harus dijalankan. Anda dapat menggunakan angka atau nama hari/bulan jika berlaku dalam spesifikasi waktu.
- Bidang dipisahkan oleh spasi atau tab.
- Koma (
,
) digunakan untuk menentukan daftar misalnya 1,4,6,8 yang artinya dijalankan pada 1,4,6,8. - Rentang ditentukan dengan tanda hubung (
-
) dan dapat digabungkan dengan daftar mis. 1-3,9-12 yang berarti antara 1 dan 3 kemudian antara 9 dan 12. /
karakter dapat digunakan untuk memperkenalkan langkah mis. 2/5 yang artinya mulai dari 2 lalu setiap 5 (2,7,12,17,22...). Mereka tidak membungkus melewati akhir.- Sebuah tanda bintang (
*
) dalam suatu bidang menandakan seluruh rentang untuk bidang itu (mis.0-59
untuk bidang menit). - Rentang dan langkah dapat digabungkan, mis.
*/2
menandakan mulai dari minimum untuk bidang yang relevan lalu setiap 2 mis. 0 untuk menit (0,2...58), 1 untuk bulan (1,3 ... 11) dll.
Men-debug perintah cron
Periksa email!
Secara default cron akan mengirimkan output apa pun dari perintah ke pengguna yang menjalankan perintah tersebut. Jika tidak ada keluaran, tidak akan ada surat. Jika Anda ingin cron mengirim email ke akun lain maka Anda dapat mengatur variabel lingkungan MAILTO di file crontab mis.
[email protected]
1 2 * * * /path/to/your/command
Rekam hasilnya sendiri
Anda dapat mengarahkan stdout dan stderr ke file. Sintaks yang tepat untuk menangkap output dapat bervariasi tergantung pada apa yang digunakan shell cron. Berikut adalah dua contoh yang menyimpan semua output ke file di /tmp/mycommand.log
:
1 2 * * * /path/to/your/command &>/tmp/mycommand.log
1 2 * * * /path/to/your/command >/tmp/mycommand.log 2>&1
Lihat log
Cron mencatat tindakannya melalui syslog, yang (tergantung pada pengaturan Anda) sering masuk ke /var/log/cron
atau /var/log/syslog
.
Jika perlu, Anda dapat memfilter pernyataan cron dengan mis.
grep CRON /var/log/syslog
Sekarang setelah kita membahas dasar-dasar cron, di mana letak file dan cara menggunakannya, mari kita lihat beberapa masalah umum.
Periksa apakah cron berjalan
Jika cron tidak berjalan maka perintah Anda tidak akan dijadwalkan ...
ps -ef | grep cron | grep -v grep
harus memberi Anda sesuatu seperti
root 1224 1 0 Nov16 ? 00:00:03 cron
atau
root 2018 1 0 Nov14 ? 00:00:06 crond
Jika tidak, mulai ulang
/sbin/service cron start
atau
/sbin/service crond start
Mungkin ada metode lain; gunakan apa yang disediakan distro Anda.
cron menjalankan perintah Anda di lingkungan terbatas.
Variabel lingkungan apa yang tersedia kemungkinan sangat terbatas. Biasanya, Anda hanya akan menentukan beberapa variabel, seperti $LOGNAME
, $HOME
, dan $PATH
.
Catatan khusus adalah PATH
dibatasi untuk /bin:/usr/bin
. Sebagian besar masalah "skrip cron saya tidak berfungsi" disebabkan oleh jalur terbatas ini . Jika perintah Anda berada di lokasi yang berbeda, Anda dapat menyelesaikannya dengan beberapa cara:
-
Berikan path lengkap ke perintah Anda.
1 2 * * * /path/to/your/command
-
Berikan PATH yang sesuai di file crontab
PATH=/bin:/usr/bin:/path/to/something/else 1 2 * * * command
Jika perintah Anda memerlukan variabel lingkungan lain, Anda juga dapat menentukannya di file crontab.
cron menjalankan perintah Anda dengan cwd ==$HOME
Di mana pun program yang Anda jalankan berada di sistem file, direktori kerja saat ini dari program saat cron dijalankan akan menjadi direktori home pengguna . Jika Anda mengakses file dalam program Anda, Anda harus mempertimbangkan hal ini jika Anda menggunakan jalur relatif, atau (sebaiknya) hanya menggunakan jalur yang sepenuhnya memenuhi syarat di mana saja, dan menyelamatkan semua orang dari banyak kebingungan.
Perintah terakhir di crontab saya tidak berjalan
Cron umumnya mengharuskan perintah diakhiri dengan baris baru. Edit crontab Anda; pergi ke akhir baris yang berisi perintah terakhir dan sisipkan baris baru (tekan enter).
Periksa format crontab
Anda tidak dapat menggunakan crontab yang diformat crontab pengguna untuk /etc/crontab atau fragmen di /etc/cron.d dan sebaliknya. Crontab yang diformat pengguna tidak menyertakan nama pengguna di posisi ke-6 berturut-turut, sedangkan crontab yang diformat sistem menyertakan nama pengguna dan menjalankan perintah sebagai pengguna tersebut.
Saya meletakkan file di /etc/cron.{hourly,daily,weekly,monthly} dan tidak berjalan
- Periksa apakah nama file tidak memiliki ekstensi lihat run-parts
- Pastikan file memiliki izin eksekusi.
- Beri tahu sistem apa yang harus digunakan saat menjalankan skrip Anda (misalnya, masukkan
#!/bin/sh
di atas)
Bug terkait tanggal Cron
Jika tanggal Anda baru-baru ini diubah oleh pengguna atau pembaruan sistem, zona waktu atau lainnya, maka crontab akan mulai berperilaku tidak menentu dan menunjukkan bug aneh, terkadang berfungsi, terkadang tidak. Ini adalah upaya crontab untuk mencoba "melakukan apa yang Anda inginkan" ketika waktu berubah dari bawahnya. Bidang "menit" akan menjadi tidak efektif setelah jam diubah. Dalam skenario ini, hanya tanda bintang yang akan diterima. Mulai ulang cron dan coba lagi tanpa terhubung ke internet (sehingga tanggal tidak memiliki kesempatan untuk mengatur ulang ke salah satu server waktu).
Tanda persen, sekali lagi
Untuk menekankan saran tentang tanda persen, berikut adalah contoh apa yang dilakukan cron dengan mereka:
# cron entry
* * * * * cat >$HOME/cron.out%foo%bar%baz
akan membuat file ~/cron.out yang berisi 3 baris
foo
bar
baz
Ini sangat mengganggu saat menggunakan date
memerintah. Pastikan untuk menghindari tanda persen
* * * * * /path/to/command --day "$(date "+\%Y\%m\%d")"
Waspadalah terhadap Sudo
saat dijalankan sebagai pengguna non-root,
crontab -e
akan membuka crontab pengguna, sedangkan
sudo crontab -e
akan membuka crontab pengguna root. Tidak disarankan untuk menjalankan perintah sudo di tugas cron, jadi jika Anda mencoba menjalankan perintah sudo di cron pengguna, coba pindahkan perintah tersebut ke cron root dan hapus sudo dari perintah.
Solusi 2:
Debian Linux dan turunannya (Ubuntu, Mint, dll) memiliki beberapa keanehan yang dapat mencegah pekerjaan cron Anda dijalankan; khususnya, file di /etc/cron.d
, /etc/cron.{hourly,daily,weekly,monthly}
harus :
- dimiliki oleh root
- hanya dapat ditulis oleh root
- tidak dapat ditulis oleh grup atau pengguna lain
- memiliki nama tanpa titik '.' atau karakter khusus lainnya selain '-' dan '_' .
Yang terakhir sering menyakiti pengguna yang tidak menaruh curiga; khususnya skrip apa pun di salah satu folder ini bernama whatever.sh
, mycron.py
, testfile.pl
, dll. tidak dieksekusi, selamanya.
Dalam pengalaman saya, poin khusus ini sejauh ini merupakan alasan paling sering untuk cronjob non-eksekusi pada Debian dan turunannya.
Lihat man cron
untuk detail lebih lanjut, jika perlu.
Solusi 3:
Jika cronjobs Anda berhenti berfungsi, periksa apakah kata sandi Anda belum kedaluwarsa., karena setelah itu, semua tugas cron berhenti.
Akan ada pesan di /var/log/messages
mirip dengan yang di bawah ini yang menunjukkan masalah dengan mengautentikasi pengguna:
(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)
Solusi 4:
Jadwal yang tidak biasa dan tidak teratur
Cron dianggap sebagai penjadwal yang sangat mendasar dan sintaksnya tidak memungkinkan administrator untuk merumuskan jadwal yang sedikit lebih tidak biasa dengan mudah.
Pertimbangkan pekerjaan berikut yang umumnya akan dijelaskan ke "run command
setiap 5 menit" :
*/5 * * * * /path/to/your/command
versus:
*/7 * * * * /path/to/your/command
yang tidak selalu jalankan command
setiap 7 menit .
Ingat bahwa / karakter dapat digunakan untuk memperkenalkan langkah tetapi langkah itu tidak melampaui akhir rangkaian, mis. */7
yang cocok setiap menit ke-7 dari menit 0-59
yaitu 0,7,14,21,28,35,42,49,56 tetapi antara satu jam dan berikutnya akan ada hanya 4 menit antara batch , setelah 00:56
seri baru dimulai dari 01:00
, 01:07
dll. (dan kumpulan tidak akan berjalan di 01:03
, 01:10
, 01:17
dll.).
Apa yang harus dilakukan?
Buat beberapa kelompok
Daripada satu cron job, buat beberapa batch yang digabungkan menghasilkan jadwal yang diinginkan.
Misalnya untuk menjalankan batch setiap 40 menit (00:00, 00:40, 01:20, 02:00 dll.) buat dua batch, satu yang berjalan dua kali pada jam genap dan yang kedua hanya berjalan pada jam ganjil:
# The following lines create a batch that runs every 40 minutes i.e.
# runs on 0:00, 0:40, 02:00, 02:40 04:00 etc to 22:40
0,40 */2 * * * /path/to/your/command
# runs on 01:20, 03:20, etc to 23:20
20 1/2 * * * /path/to/your/command
# Combined: 0:00, 0:40, 01:20, 02:00, 02:40, 03:20, 04:00 etc.
Jalankan kumpulan Anda lebih jarang
Daripada menjalankan batch Anda setiap 7 menit, yang merupakan jadwal yang sulit untuk dipecah menjadi beberapa batch, jalankan saja setiap 10 menit.
Mulai batch Anda lebih sering (tetapi cegah beberapa batch berjalan secara bersamaan)
Banyak jadwal aneh berkembang karena waktu proses batch meningkat/berfluktuasi dan kemudian batch dijadwalkan dengan sedikit margin keamanan tambahan untuk mencegah proses berikutnya dari batch yang sama tumpang tindih dan berjalan secara bersamaan.
Alih-alih, pikirkan secara berbeda dan buat cronjob yang akan gagal dengan baik ketika proses sebelumnya belum selesai, tetapi akan berjalan sebaliknya. Lihat T&J ini:
* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job
Itu akan segera memulai proses baru setelah proses /usr/local/bin/frequent_cron_job sebelumnya telah selesai.
Mulai batch Anda lebih sering (tetapi keluar dengan anggun saat kondisinya tidak tepat)
Karena sintaks cron terbatas, Anda dapat memutuskan untuk menempatkan kondisi dan logika yang lebih kompleks dalam tugas batch itu sendiri (atau dalam skrip pembungkus di sekitar pekerjaan batch yang ada). Itu memungkinkan Anda untuk memanfaatkan kemampuan lanjutan dari bahasa skrip favorit Anda, untuk mengomentari kode Anda dan akan mencegah konstruksi yang sulit dibaca di entri crontab itu sendiri.
Di bash, seven-minute-job
kemudian akan terlihat seperti sesuatu seperti:
#!/bin/bash
# seven-minute-job
# This batch will only run when 420 seconds (7 min) have passed
# since the file /tmp/lastrun was either created or updated
if [ ! -f /tmp/lastrun ] ; then
touch /tmp/lastrun
fi
if [ $(( $(date +%s) - $(date -r /tmp/lastrun +%s) )) -lt 420 ] ; then
# The minimum interval of 7 minutes between successive batches hasn't passed yet.
exit 0
fi
#### Start running your actual batch job below
/path/to/your/command
#### actual batch job is done, now update the time stamp
date > /tmp/lastrun
#EOF
Yang kemudian dapat Anda (coba) jalankan dengan aman setiap menit:
* * * * * /path/to/your/seven-minute-job
Masalah yang berbeda, tetapi serupa akan menjadwalkan batch untuk dijalankan pada hari Senin pertama setiap bulan (atau Rabu kedua) dll. Cukup jadwalkan batch untuk dijalankan setiap hari Senin dan keluar saat tanggal bukan antara 1 atau 7 dan hari minggu ini bukan hari Senin.
#!/bin/bash
# first-monday-of-the-month-housekeeping-job
# exit if today is not a Monday (and prevent locale issues by using the day number)
if [ $(date +%u) != 1 ] ; then
exit 0
fi
# exit if today is not the first Monday
if [ $(date +%d) -gt 7 ] ; then
exit 0
fi
#### Start running your actual batch job below
/path/to/your/command
#EOF
Yang kemudian dapat Anda (coba) jalankan dengan aman setiap hari Senin:
0 0 * * 1 /path/to/your/first-monday-of-the-month-housekeeping-job
Jangan gunakan cron
Jika kebutuhan Anda kompleks, Anda dapat mempertimbangkan untuk menggunakan produk yang lebih canggih yang dirancang untuk menjalankan jadwal yang kompleks (didistribusikan melalui beberapa server) dan yang mendukung pemicu, ketergantungan pekerjaan, penanganan kesalahan, coba ulang dan coba lagi pemantauan, dll. Jargon industri akan menjadi "perusahaan " penjadwalan tugas dan/atau "otomatisasi beban kerja".
Solusi 5:
khusus PHP
Jika Anda memiliki beberapa tugas cron seperti:
php /bla/bla/something.php >> /var/logs/somelog-for-stdout.log
Dan jika terjadi kesalahan diharapkan, bahwa mereka akan dikirimkan kepada Anda, tetapi tidak -- periksa ini.
PHP secara default tidak mengirim kesalahan ke STDOUT. @lihat https://bugs.php.net/bug.php?id=22839
Untuk memperbaikinya, tambahkan di cli`s php.ini atau di baris Anda (atau di pembungkus bash Anda untuk PHP) ini:
- --define display_startup_errors=1
- --define display_errors='stderr'
Pengaturan ke-1 akan memungkinkan Anda memiliki fatal seperti 'Memory oops' dan ke-2 -- untuk mengalihkan semuanya ke STDERR. Hanya setelah Anda bisa tidur nyenyak karena semua akan dikirim ke email root Anda, bukan hanya login.