Cron job dan waktu acak, dalam jam tertentu

101

Saya membutuhkan kemampuan untuk menjalankan skrip PHP 20 kali sehari pada waktu yang benar-benar acak. Saya juga ingin itu hanya berjalan antara jam 9 pagi - 11 malam.

Saya terbiasa membuat cron job di linux.

floatleft
sumber
1
Pertanyaannya tidak diajukan dengan baik. Akhirnya Anda ingin mendistribusikan 20 titik pada sumbu waktu antara jam 9 pagi dan 11 pagi. Tetapi apakah ada kendala pada perbedaan waktu minimum? Apakah tidak melakukan apa pun antara pukul 09.00 dan 10.30 diperbolehkan? Satu-satunya cara untuk melakukan ini menurut ide Klaus: pilih 20 waktu Anda pada pukul 09:00, yang memungkinkan Anda untuk memenuhi batasan apa pun yang mungkin Anda miliki, lalu jadwalkan hal-hal dengan "pada".
David Tonhofer

Jawaban:

38

Jika saya mengerti apa yang Anda cari, Anda perlu melakukan sesuatu yang sedikit berantakan, seperti memiliki tugas cron yang menjalankan skrip bash yang mengacak waktu proses ... Sesuatu seperti ini:

crontab:

0 9 * * * /path/to/bashscript

dan di / path / ke / bashscript:

#!/bin/bash

maxdelay=$((14*60))  # 14 hours from 9am to 11pm, converted to minutes
for ((i=1; i<=20; i++)); do
    delay=$(($RANDOM%maxdelay)) # pick an independent random delay for each of the 20 runs
    (sleep $((delay*60)); /path/to/phpscript.php) & # background a subshell to wait, then run the php script
done

Beberapa catatan: pendekatan ini sedikit boros sumber daya, karena menjalankan 20 proses latar belakang pada jam 9 pagi, yang masing-masing menunggu beberapa menit secara acak (hingga 14 jam, yaitu jam 11 malam), kemudian meluncurkan skrip php dan keluar. Selain itu, karena ini menggunakan jumlah menit acak (bukan detik), waktu mulai tidak seacak mungkin. Tapi $ ACAK hanya naik menjadi 32.767, dan ada 50.400 detik antara jam 9 pagi dan 11 malam, akan sedikit lebih rumit untuk mengacak detik juga. Terakhir, karena waktu mulai acak dan tidak bergantung satu sama lain, mungkin (tetapi tidak sangat mungkin) dua atau lebih contoh skrip akan dimulai secara bersamaan.

Gordon Davisson
sumber
2
Anda dapat membuat tugas aritmatika lebih mudah dibaca dengan menghilangkan tanda dolar dan memindahkan tanda kurung ganda ke kiri (mis. ((maxdelay = 14 * 60))Atau ((delay = $RANDOM % maxdelay))). The sleepArgumen masih perlu cara Anda memilikinya (meskipun Anda bisa menambahkan spasi, jika diinginkan).
Dijeda sampai pemberitahuan lebih lanjut.
1
Ini berhasil juga untuk saya. Skrip bash kustom saya terlihat seperti di bawah ini sleep $[ ( $RANDOM % 60 ) + 1 ]s && some_script.sh
Shyam Habarakada
Apakah saya melewatkan sesuatu atau penundaan maksimum harus diatur ke maxdelay = $ ((14 *
60/20
@jenishSakhiya Penundaan acak untuk masing-masing dari 20 sesi adalah mutlak (baik, mulai pukul 9 pagi), tidak relatif terhadap proses lainnya. Artinya, jika salah satu penundaan acak muncul sebagai 13 jam, itu berarti penundaan akan berjalan pada pukul 10 malam (13 jam setelah 9 pagi), bukan 13 jam setelah penundaan yang lain.
Gordon Davisson
139

Ya, ya, pertanyaannya sudah lebih dari satu tahun, tapi mungkin saya bisa menambahkan sesuatu yang berguna:

Bagaimana cara membuat sesuatu secara acak 20 kali sehari antara jam 9 pagi dan 11 malam? Itu agak rumit dalam cron, karena Anda membagi 14 jam dengan 20 kali eksekusi. Saya tidak terlalu menyukai jawaban lain karena mereka memerlukan penulisan skrip bash wrapper untuk skrip php Anda.

Namun, jika Anda mengizinkan saya untuk mengurangi pembatasan waktu dan frekuensi menjadi 13 kali antara jam 8:30 pagi dan 11:09 malam, ini mungkin berhasil, dan semuanya dalam batasan crontab Anda:

30 8-21/* * * * sleep ${RANDOM:0:2}m ; /path/to/script.php

$ {ACAK: 3: 2} menggunakan $ ACAK bash yang telah disebutkan orang lain di atas, tetapi menambahkan bash array slicing. Karena variabel bash tidak diketik, angka 16-bit bertanda pseudo-random akan dipotong ke 2 pertama dari 5 digit desimalnya, memberi Anda satu baris ringkas untuk menunda cronjob Anda antara 10 dan 99 menit (meskipun distribusinya bias ke arah 10 hingga 32).

Hal berikut mungkin juga berhasil untuk Anda, tetapi menurut saya memang "kurang acak" karena beberapa alasan (mungkin Hukum Benford dipicu oleh pemodulasian bilangan acak semu. Hei, saya tidak tahu, saya gagal dalam matematika ... Salahkan di pesta!):

30 8-21/* * * * sleep $[RANDOM\%90]m ; /path/to/script.php

Anda perlu merender modulus sebagai '\%' di atas karena cron (yah, setidaknya Linux 'vixie-cron') mengakhiri baris ketika menemukan '%' yang tidak dapat dihilangkan.

Mungkin Anda bisa mendapatkan 7 eksekusi skrip yang tersisa di sana dengan menambahkan baris lain dengan rentang 7 jam lainnya. Atau kendurkan batasan Anda untuk berlari antara jam 3 pagi dan 11 malam.

al-x
sumber
4
Saya suka jawaban yang terlambat. Tetapi jika Anda mencoba untuk menghasilkan bilangan bulat acak yang didistribusikan secara merata dalam kisaran 10 hingga 99, dan keluaran RANDOM adalah 0 hingga 32.767, mengapa Anda tidak melakukannya $[(RANDOM/368)+10]?
jsdalton
3
@jsdalton: Bukankah operator modulo lebih baik? $((RANDOM % 90 + 10))Tes:for i in {0..9999}; do echo $((RANDOM % 90 + 10)); done | sort | uniq -c
geon
5
Pada banyak sistem cron tidak menggunakan bash secara default sehingga bisa lebih baik untuk menghindari bashism yang $RANDOM: sleep $(( $(od -N1 -tuC -An /dev/urandom) \% 90 ))m.
pabouk
9
Pastikan yang crontabdigunakan bashsebelum Anda menggunakan $RANDOM. Jika Anda memiliki vixie-cron(tampaknya kasus saya di Ubuntu), maka Anda dapat menambahkan SHELL=/bin/bashke atas. Ada lebih banyak alternatif untuk versi cron lainnya di sini: superuser.com/a/264541/260350
DaAwesomeP
1
Ketika saya menggunakan saran pertama di atas, saya mendapatkan crontab: errors in crontab file, can't install. Do you want to retry the same edit?bantuan
Seano
72

Jadi saya menggunakan yang berikut ini untuk menjalankan perintah antara 1AM dan 330AM

0 1 * * * perl -le 'sleep rand 9000' && *command goes here*

Itu telah memenuhi kebutuhan acak saya untuk saya. Itu berarti 9.000 detik == 150 menit == 2,5 jam

Dave
sumber
8
:: MindBLOWN :: tempat lain yang tidak jelas untuk menggunakan sedikit perl.
Mark Carpenter Jr
Ini jelas merupakan jawaban terbersih
Enrico Detoma
Ini agak tidak efisien, karena Anda membuat banyak proses.
kahveciderin
21

Cron menawarkan RANDOM_DELAYvariabel. Lihat crontab(5)detailnya.

Variabel RANDOM_DELAY memungkinkan penundaan permulaan pekerjaan dengan jumlah menit acak dengan batas atas yang ditentukan oleh variabel.

Ini terlihat secara umum dalam anacronpekerjaan, tetapi juga dapat berguna dalam a crontab.

Anda mungkin perlu berhati-hati dengan ini jika Anda memiliki beberapa pekerjaan yang berjalan dengan perincian (menit) yang baik dan pekerjaan lain yang kasar.

Micah Elliott
sumber
Saya ingin menggunakan variabel RANDOM_DELAY, tetapi tidak dapat menemukan petunjuk apa pun di halaman manual crontab (5) di Ubuntu 14.04.4 LTS.
Exocom
Itu sangat disayangkan. Saya ingin tahu apakah itu tidak didukung di sana. Saya melihatnya didokumentasikan di halaman manual di Centos 7 dan Arch Linux.
Micah Elliott
9
ini sepertinya jawaban yang benar tetapi dapatkah Anda memberi contoh?
chovy
14
Harap dicatat bahwa RANDOM_DELAYitu dibuat sekali dan tetap konstan untuk seluruh runtime daemon.
Maciej Swic
5
The RANDOM_DELAYbendera adalah fitur dari cronie-crond sementara Ubuntu tampaknya berjalan vixie-cronyang tidak memiliki bendera ini.
kravietz
7

Pikiran pertama saya adalah membuat satu pekerjaan cron yang meluncurkan 20 pekerjaan yang dijadwalkan secara acak. The atutilitas (http://unixhelp.ed.ac.uk/CGI/man-cgi?at) digunakan untuk mengeksekusi perintah pada waktu yang ditentukan.

klaus
sumber
Contoh penggunaan di ada di sini: stackoverflow.com/a/6136145/803174
Kangur
6

Saya akhirnya menggunakan sleep $(( 1$(date +%N) % 60 )) ; dostuffs (kompatibel dengan bash & sh)

Awalan 1 adalah untuk memaksa interpretasi NON basis 8 tanggal +% N (misalnya 00551454)

Jangan lupa untuk keluar% menggunakan \% dalam file crontab

* * * * *  nobody  sleep $(( 1$(date +\%N) \% 60 )) ; dostuffs 
131
sumber
2
Jika seseorang bertanya-tanya, seperti saya:% N memberikan nanos saat ini, tetapi beberapa halaman manual kekurangan informasi untuk itu. Ini adalah solusi yang sangat cerdas untuk orang-orang yang hanya membutuhkan "beberapa keacakan" dengan mudah per perintah.
Thorsten Schöning
Terlepas dari peringatan yang sudah dibahas di tempat lain, ini hanya akan berfungsi jika Anda memiliki GNU date(yang mungkin Anda lakukan di sebagian besar Linux, tetapi tidak di Busybox, MacOS standar, atau berbagai platform turunan BSD lainnya).
tripleee
4

Solusi al-x tidak bekerja untuk saya karena perintah crontab tidak dijalankan di bash tetapi di sh saya kira. Apa yang berhasil adalah:

30 8 * * * bash -c "sleep $[RANDOM\%90]m" ; /path/to/script.py
Wilbert
sumber
Saya mencoba segalanya dan tetap tidak berhasil. Anda memposting menjelaskan mengapa, terima kasih!
marlar
$[ ... ]sudah usang sintaks sejak waaaay kembali; untuk apa pun dari milenium ini, Anda akan lebih memilih $((RANDOM\%90))msintaks yang kompatibel dengan POSIX (tetapi tentu saja RANDOMmasih hanya Bash).
tripleee
1

at -f [file] [timespec]

atau

echo [command] | at [timespec]

atau

at [timespec] ... dan spesifikasi interaktif seperti script rekaman.

Perintah

At menjalankan teks yang disediakan di stdin atau dalam file yang ditentukan oleh -f [file].

Timespec

Berikut [timespec] tata bahasanya . Bisa jadi seperti ini:

  • Waktu 24 jam sebagai 4-digit int, misalnya 0100, 2359,1620
  • now + 10 minutes
  • 2071-05-31 - 5 hours 12 minutes UTC

Jika Anda secara eksplisit menentukan zona waktu, beberapa versi timespec mungkin hanya memungkinkan UTCuntuk argumen zona waktu opsional.

Contoh

cat script.sh | at now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

at -f script.sh now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

Cobalah ...

Anda dapat menguji penguraian bash dengan melakukan pra-tunggu echodan keluar dari |(pipa).

echo cat script.sh \| at now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

echo at -f script.sh now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

Untuk melihat pekerjaan yang dijadwalkan, gunakan atqdan isi pekerjaan (lingkungan vars, setup, dan perintah / skrip) dengan at -c [jobid].

Catatan

Sistem adalah bagian dari cron, dan prompt interaktif benar-benar menangkap seluruh status shell Anda saat ini, sehingga Anda dapat menjalankan perintah tanpa menentukan jalur absolut.

mcint
sumber
0

Bagi yang googling caranya disini:

Jika Anda menggunakan anacron (desktop dan laptop Ubuntu), Anda dapat mengedit

/etc/anacrontab

dan tambahkan

RANDOM_DELAY=XX 

Di mana XX adalah jumlah menit Anda ingin menunda pekerjaan dasar.

Anacron seperti cron tetapi tidak mengharapkan komputer Anda dalam 24x7 (seperti laptop kami) dan akan menjalankan skrip yang terlewat karena sistem sedang down.

Ganesh Krishnan
sumber
0

Anda dapat mencoba dengan contoh ini untuk menggunakan waktu acak sebelum menjalankan perintah:

#!/bin/bash
# start time
date +"%H:%M:%S"

# sleep for 5 seconds
sleep $(shuf -i 1-25 -n 1)
# end time
date +"%H:%M:%S"
Houssin Boulla
sumber
0

Bagaimana dengan membuat skrip yang menulis ulang crontab setiap hari?

  1. Baca cron saat ini (A)
  2. Pilih waktu acak (B)
  3. Tulis kembali cron sebelumnya (A), tambahkan cron acak baru (B)
  4. Pastikan untuk menambahkan ke cron untuk menjalankan skrip ini sejak awal.
mellofellow
sumber
2
Jangan mengelak dari sistem reputasi dengan memposting komentar sebagai jawaban. Namun komentar Anda terlihat cukup bagus untuk benar - benar menjadi jawaban. Saya sarankan untuk menghapus " Saya tidak memiliki perwakilan untuk menambahkan komentar, tapi ".
Ted Lyngmo
1
Saya baru saja meninjau jawaban ini dan melewatkan bagian di mana Anda mengajukan pertanyaan sebagai imbalan di bagian akhir (pekerjaan ceroboh di pihak saya). Jangan bertanya dalam jawaban. Posting pertanyaan Anda sendiri untuk pertanyaan yang Anda miliki. Saya membuat pertanyaan semi Anda menjadi sesuatu yang bisa menjadi jawaban.
Ted Lyngmo
1
Mengerti! Terima kasih. Saya akan lebih berhati-hati lain kali, tidak ada niat buruk yang dimaksudkan.
mellofellow
1
Saya yakin Anda tidak memiliki niat buruk dan Anda tidak perlu terlalu berhati-hati. Anda menguraikan solusi yang mungkin - dan sedikit tersandung di bagian akhir. Jangan khawatir!
Ted Lyngmo
0

Saya menyadari ini adalah utas yang lebih lama, tetapi saya ingin menambahkan satu hal terkait nilai acak yang sering saya gunakan. Alih-alih menggunakan variabel $ RANDOM dengan rentang tetap dan terbatas, saya sering membuat nilai acak rentang acak di shell dengan

dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -N4 -t u4 -A none

jadi Anda bisa melakukannya, misalnya,

FULLRANDOM=$(dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -N4 -t u4 -A none)

dan mengatasi beberapa batasan yang dibahas di utas ini.

MLP
sumber
1
Selamat datang di SO. Nah, utas lama atau tidak, ini mengirim saya ke ~$info dddan saya bisa mengerti apa yang terjadi di sisi kiri |, tetapi tidak bisa melihat sisi kanan. Jadi, bagi saya dan orang lain yang tertarik pada overcoming some restrictionspembuatan nilai acak, mengapa tidak meluangkan waktu sejenak untuk menjelaskan RHS, dan membuat promosi yang lebih kuat untuk menggunakan pendekatan Anda. Kedalaman penjelasannya membuat orang nyaman dengan proses yang Anda sarankan dan manfaatnya. Terima kasih.
Chris
Ah ok. od aka "octal dump" mengambil file atau stdin dan membuang data biner dalam bentuk yang dapat dibaca manusia. Kami ingin nomor kami ditampilkan sebagai desimal tak bertanda (-t u4), dan tidak ingin indeks alamat (-A tidak ada). -N4 adalah redundan karena kami hanya mengambil 4 byte, tetapi juga tidak merugikan. Saya harap ini menjelaskannya ...
MLP