งาน Cron และเวลาสุ่มภายในไม่กี่ชั่วโมง


103

ฉันต้องการความสามารถในการเรียกใช้สคริปต์ PHP 20 ครั้งต่อวันในเวลาสุ่มอย่างสมบูรณ์ ฉันยังต้องการให้มันทำงานระหว่าง 9.00 น. - 23.00 น. เท่านั้น

ฉันคุ้นเคยกับการสร้างงาน cron ใน linux


1
คำถามไม่ได้ถูกวางไว้อย่างดี ในที่สุดคุณต้องการกระจาย 20 จุดบนแกนเวลาระหว่าง 9.00 น. ถึง 11.00 น. แต่มีข้อ จำกัด เกี่ยวกับความแตกต่างของเวลาขั้นต่ำหรือไม่? การทำอะไรระหว่าง 9.00 - 10.30 น. เป็นที่ยอมรับหรือไม่? วิธีเดียวที่จะทำให้สิ่งนี้เป็นไปได้สำหรับแนวคิดของ Klaus: เลือก 20 ครั้งของคุณในเวลา 09:00 น. ซึ่งจะช่วยให้คุณปฏิบัติตามข้อ จำกัด ที่คุณมีได้จากนั้นกำหนดเวลาสิ่งต่างๆด้วย "at"
David Tonhofer

คำตอบ:


39

ถ้าฉันเข้าใจสิ่งที่คุณกำลังมองหาคุณจะต้องทำอะไรบางอย่างที่ยุ่งเหยิงเช่นมีงาน cron ที่เรียกใช้สคริปต์ทุบตีที่สุ่มเวลารัน ... อะไรทำนองนี้:

crontab:

0 9 * * * /path/to/bashscript

และใน / path / to / 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

ข้อสังเกตบางประการ: วิธีนี้เป็นการสิ้นเปลืองทรัพยากรเล็กน้อยเนื่องจากจะทำให้กระบวนการพื้นหลัง 20 กระบวนการทำงานในเวลา 9.00 น. ซึ่งแต่ละกระบวนการรอเป็นเวลาสุ่มเป็นเวลาหลายนาที (สูงสุด 14 ชั่วโมงเช่น 23.00 น.) จากนั้นเปิดสคริปต์ php และ ออก นอกจากนี้เนื่องจากใช้จำนวนนาทีแบบสุ่ม (ไม่ใช่วินาที) เวลาเริ่มต้นจึงไม่สุ่มเท่าที่ควร แต่ $ RANDOM จะสูงถึง 32,767 เท่านั้นและมีเวลา 50,400 วินาทีระหว่าง 9.00 น. ถึง 23.00 น. การสุ่มวินาทีจะซับซ้อนกว่าเล็กน้อยเช่นกัน ในที่สุดเนื่องจากเวลาเริ่มต้นเป็นแบบสุ่มและเป็นอิสระจากกันจึงเป็นไปได้ (แต่ไม่น่าจะเป็นไปได้มากนัก) ที่สคริปต์สองอินสแตนซ์หรือมากกว่านั้นจะเริ่มต้นพร้อมกัน


2
คุณสามารถทำให้การกำหนดเลขคณิตอ่านง่ายขึ้นโดยการวางเครื่องหมายดอลลาร์แล้วเลื่อนคู่ parens ไปทางซ้าย (เช่น((maxdelay = 14 * 60))หรือ((delay = $RANDOM % maxdelay))) sleepอาร์กิวเมนต์ยังคงต้องการที่จะเป็นวิธีการที่คุณมีมัน (แม้ว่าคุณสามารถเพิ่มช่องว่างถ้าต้องการ)
หยุดชั่วคราวจนกว่าจะมีประกาศอีกครั้ง

1
สิ่งนี้ได้ผลสำหรับฉันด้วย สคริปต์ทุบตีที่กำหนดเองของฉันมีลักษณะดังนี้ sleep $[ ( $RANDOM % 60 ) + 1 ]s && some_script.sh
Shyam Habarakada

ฉันขาดอะไรไปหรือควรตั้งค่าความล่าช้าสูงสุดเป็น maxdelay = $ ((14 *
60/20

@jenishSakhiya ความล่าช้าแบบสุ่มสำหรับแต่ละการวิ่ง 20 ครั้งนั้นแน่นอน (เริ่มตั้งแต่เวลา 9.00 น.) ไม่สัมพันธ์กับการวิ่งอื่น นั่นคือหากความล่าช้าแบบสุ่มเกิดขึ้นเป็น 13 ชั่วโมงนั่นหมายความว่าจะทำงานในเวลา 22.00 น. (13 ชั่วโมงหลัง 9.00 น.) ไม่ใช่ 13 ชั่วโมงหลังจากการวิ่งอื่น ๆ
Gordon Davisson

143

ใช่คำถามนี้มีอายุมากกว่าหนึ่งปีแล้ว แต่ฉันอาจจะเพิ่มสิ่งที่มีประโยชน์:

จะ cron บางสิ่งบางอย่างโดยสุ่มชดเชย 20 ครั้งต่อวันระหว่าง 9.00 น. ถึง 23.00 น. นั่นค่อนข้างยุ่งยากภายใน cron เพราะคุณหาร 14 ชั่วโมงด้วย 20 ครั้งในการดำเนินการ ฉันไม่ชอบคำตอบอื่น ๆ มากนักเพราะต้องเขียนสคริปต์ bash wrapper สำหรับสคริปต์ php ของคุณ

อย่างไรก็ตามหากคุณยอมให้ฉันมีอิสระในการลดเวลาและการ จำกัด ความถี่เป็น 13 ครั้งระหว่าง 08:30 น. ถึง 23:09 น. นี่อาจเป็นกลอุบายและทั้งหมดนี้อยู่ในขอบเขตของ crontab ของคุณ:

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

$ {RANDOM: 3: 2} ใช้ $ RANDOM ของ bash ที่คนอื่นพูดถึงข้างต้น แต่เพิ่มการแบ่งส่วน bash array เนื่องจากตัวแปร bash ไม่ได้ถูกพิมพ์ตัวเลข 16 บิตที่ลงชื่อแบบสุ่มหลอกจะถูกตัดทอนให้เหลือ 2 หลักแรกจากทศนิยม 5 หลักทำให้คุณมีหนึ่งซับสั้น ๆ สำหรับการหน่วงเวลา cronjob ระหว่าง 10 ถึง 99 นาที (แม้ว่าการแจกแจงจะเอนเอียงไปทาง 10 ถึง 32)

สิ่งต่อไปนี้อาจใช้ได้ผลสำหรับคุณเช่นกัน แต่ฉันพบว่ามัน "สุ่มน้อยกว่า" ด้วยเหตุผลบางประการ (บางทีกฎของ Benford อาจเกิดจากการปรับตัวเลขสุ่มหลอกเฮ้ฉันไม่รู้ฉันเข้าใจคณิตศาสตร์ ... ทุบตี!):

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

คุณต้องแสดงโมดูลัสเป็น '\%' ด้านบนเนื่องจาก cron (อย่างน้อยก็คือ 'vixie-cron' ของ Linux) จะยุติบรรทัดเมื่อพบ '%' ที่ไม่มีค่า Escape

บางทีคุณอาจได้รับการดำเนินการสคริปต์ที่เหลืออีก 7 รายการโดยการเพิ่มอีกบรรทัดด้วยช่วง 7 ชั่วโมงอีกครั้ง หรือผ่อนคลายข้อ จำกัด ของคุณให้วิ่งระหว่าง 03.00 น. ถึง 23.00 น.


4
ฉันชอบคำตอบที่ล่าช้า แต่ถ้าคุณพยายามสร้างจำนวนเต็มสุ่มที่กระจายเท่า ๆ กันในช่วง 10 ถึง 99 และผลลัพธ์ของ RANDOM คือ 0 ถึง 32,767 ทำไมคุณไม่ทำ$[(RANDOM/368)+10]ล่ะ?
jsdalton

3
@jsdalton: ตัวดำเนินการโมดูโลจะดีกว่าไม่ใช่เหรอ? $((RANDOM % 90 + 10))ทดสอบ:for i in {0..9999}; do echo $((RANDOM % 90 + 10)); done | sort | uniq -c
geon

5
ในระบบหลาย cron ไม่ได้ใช้ทุบตีโดยปริยายดังนั้นมันอาจจะดีกว่าที่จะหลีกเลี่ยง bashism :$RANDOM sleep $(( $(od -N1 -tuC -An /dev/urandom) \% 90 ))m
pabouk

9
ตรวจสอบให้แน่ใจว่าcrontabมีการใช้ก่อนที่คุณใช้bash $RANDOMหากคุณมีvixie-cron(ดูเหมือนจะเป็นกรณีของฉันบน Ubuntu) คุณสามารถเพิ่มSHELL=/bin/bashไปที่ด้านบน มีทางเลือกเพิ่มเติมสำหรับ cron เวอร์ชันอื่นที่นี่: superuser.com/a/264541/260350
DaAwesomeP

1
เมื่อฉันใช้คำแนะนำแรกข้างต้นฉันcrontab: errors in crontab file, can't install. Do you want to retry the same edit?ขอความช่วยเหลือ
Seano

73

ดังนั้นฉันใช้สิ่งต่อไปนี้เพื่อเรียกใช้คำสั่งระหว่าง 1AM ถึง 330AM

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

นั่นดูแลความต้องการสุ่มของฉันสำหรับฉัน นั่นคือ 9000 วินาที == 150 นาที == 2.5 ชั่วโมง


8
:: MindBLOWN :: อีกหนึ่งสถานที่ที่ไม่ชัดเจนในการใช้ perl เล็กน้อย
Mark Carpenter Jr

นี่เป็นคำตอบที่สะอาดที่สุดอย่างแน่นอน
Enrico Detoma

นี่เป็นวิธีที่ไม่มีประสิทธิภาพเนื่องจากคุณกำลังสร้างกระบวนการจำนวนมาก
kahveciderin

21

Cron เสนอRANDOM_DELAYตัวแปร ดูcrontab(5)รายละเอียด

ตัวแปร RANDOM_DELAY ช่วยให้การเริ่มต้นงานล่าช้าโดยการสุ่มจำนวนนาทีโดยมีขีด จำกัด สูงสุดที่ตัวแปรระบุไว้

สิ่งนี้พบเห็นได้ทั่วไปในanacronงาน แต่ยังมีประโยชน์ในไฟล์crontab .

คุณอาจต้องระวังเรื่องนี้หากคุณมีงานบางอย่างที่ทำงานด้วยความละเอียด (นาที) และงานอื่น ๆ ที่มีความหยาบ


ฉันชอบที่จะใช้ตัวแปร RANDOM_DELAY แต่ไม่พบคำแนะนำใด ๆ ใน manpage ของ crontab (5) บน Ubuntu 14.04.4 LTS
Exocom

ที่โชคร้าย ฉันสงสัยว่ามันไม่รองรับที่นั่น ฉันเห็นมันถูกบันทึกไว้ใน manpage นั้นบน Centos 7 และ Arch Linux
Micah Elliott

9
ดูเหมือนจะเป็นคำตอบที่ถูกต้อง แต่คุณสามารถใส่ตัวอย่างได้หรือไม่?
chovy

14
โปรดทราบว่าRANDOM_DELAYสร้างขึ้นครั้งเดียวและคงที่สำหรับรันไทม์ทั้งหมดของ daemon
Maciej Swic

5
RANDOM_DELAYธงเป็นคุณลักษณะของcronie-crondขณะที่อูบุนตูที่ดูเหมือนว่าจะทำงานvixie-cronซึ่งขาดธงนี้
kravietz

7

ความคิดแรกของฉันคือการสร้างงาน cron หนึ่งงานโดยเปิด 20 งานแบบสุ่มที่กำหนดไว้ในงาน atยูทิลิตี้ (http://unixhelp.ed.ac.uk/CGI/man-cgi?at) จะใช้สำหรับการรันคำสั่งในเวลาที่กำหนด


ตัวอย่างการใช้งานที่นี่: stackoverflow.com/a/6136145/803174
Kangur

7

ฉันใช้ sleep $(( 1$(date +%N) % 60 )) ; dostuffs (เข้ากันได้กับ bash & sh)

คำนำหน้า 1 คือการบังคับให้ NON ฐาน 8 ตีความวันที่ +% N (เช่น 00551454)

อย่าลืมหนี% โดยใช้ \% ในไฟล์ crontab

* * * * *  nobody  sleep $(( 1$(date +\%N) \% 60 )) ; dostuffs 

2
ถ้ามีคนสงสัยเหมือนฉัน:% N ให้นาโนเมตรปัจจุบัน แต่หน้าคนบางหน้าขาดข้อมูล นี่เป็นวิธีแก้ปัญหาที่ชาญฉลาดมากสำหรับผู้ที่ต้องการ "การสุ่ม" อย่างง่ายดายต่อคำสั่ง
Thorsten Schöning

นอกเหนือจากคำเตือนที่กล่าวถึงในที่อื่นแล้วสิ่งนี้จะใช้ได้เฉพาะเมื่อคุณมี GNU date(ซึ่งคุณอาจทำบน Linux ส่วนใหญ่ แต่ไม่ใช่บน Busybox, MacOS มาตรฐานหรือแพลตฟอร์มที่ได้รับ BSD อื่น ๆ )
tripleee

4

โซลูชันของ al-x ไม่ได้ผลสำหรับฉันเนื่องจากคำสั่ง crontab ไม่ได้ดำเนินการใน bash แต่ฉันเดาว่าใน sh งานคืออะไร:

30 8 * * * bash -c "sleep $[RANDOM\%90]m" ; /path/to/script.py

ฉันลองทุกอย่างแล้ว แต่ก็ยังไม่ได้ผลสำหรับฉัน คุณโพสต์อธิบายว่าทำไมขอบคุณ!
marlar

$[ ... ]เป็นไวยากรณ์ที่เลิกใช้แล้วเนื่องจาก waaaay กลับมา สำหรับทุกสิ่งจากสหัสวรรษนี้คุณต้องการ$((RANDOM\%90))mไวยากรณ์ที่เข้ากันได้กับ POSIX (แต่แน่นอนว่าRANDOMยังคงเป็น Bash เท่านั้น)
tripleee

1

at -f [file] [timespec]

หรือ

echo [command] | at [timespec]

หรือ

at [timespec]... และข้อกำหนดเชิงโต้ตอบเช่นscriptการบันทึก

คำสั่ง

ที่รันข้อความระบุบนstdinหรือในไฟล์ที่ระบุโดย-f [file].

Timespec

นี่คือไวยากรณ์[timespec] อาจเป็นสิ่งที่ต้องการ:

  • เวลา 24 ชั่วโมงเป็น int 4 หลักเช่น0100, 2359,1620
  • now + 10 minutes
  • 2071-05-31 - 5 hours 12 minutes UTC

หากคุณระบุเขตเวลาอย่างชัดเจน ไทม์สเปคบางเวอร์ชันอาจอนุญาตเฉพาะUTCอาร์กิวเมนต์เขตเวลาที่ไม่บังคับ

ตัวอย่าง

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

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

ลองดู ...

คุณสามารถทดสอบการแยกวิเคราะห์ bash ได้โดยรอดำเนินการล่วงหน้าechoและออกจาก|(ไปป์)

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

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

หากต้องการดูงานที่กำหนดเวลาไว้ให้ใช้ atqและเนื้อหางาน (สภาพแวดล้อม vars การติดตั้งและคำสั่ง / script) at -c [jobid]ด้วย

บันทึก

ระบบเป็นส่วนหนึ่งของ cron และพรอมต์แบบโต้ตอบจะจับสถานะปัจจุบันทั้งหมดของเชลล์ของคุณดังนั้นคุณจึงสามารถรันคำสั่งได้โดยไม่ต้องระบุพา ธ สัมบูรณ์


1

ฉันรู้ว่ามันเป็นเธรดที่เก่ากว่า แต่ฉันต้องการเพิ่มสิ่งที่เกี่ยวข้องกับค่าสุ่มที่ฉันใช้บ่อยมาก แทนที่จะใช้ตัวแปร $ RANDOM ที่มีช่วงคงที่และ จำกัด ฉันมักจะสร้างค่าสุ่มช่วงโดยพลการในเชลล์ด้วย

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

ดังนั้นคุณสามารถทำได้ตัวอย่างเช่น

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

และเอาชนะข้อ จำกัด บางประการที่กล่าวถึงในหัวข้อนี้


1
ยินดีต้อนรับสู่ SO ด้ายเก่าหรือไม่สิ่งนี้ส่งฉันไป~$info ddและฉันเข้าใจสิ่งที่เกิดขึ้นทางด้านซ้ายของ|แต่ไม่สามารถแยกออกทางด้านขวาได้ ดังนั้นสำหรับฉันและคนอื่น ๆ ที่สนใจในovercoming some restrictionsการสร้างมูลค่าแบบสุ่มทำไมไม่ใช้เวลาสักครู่เพื่ออธิบาย RHS และทำการเสนอขายที่แข็งแกร่งขึ้นเพื่อใช้แนวทางของคุณ คำอธิบายเชิงลึกทำให้ผู้คนรู้สึกสบายใจกับกระบวนการที่คุณแนะนำและประโยชน์ที่ได้รับขอบคุณ
คริส

1
อาโอเค. od aka "การถ่ายโอนข้อมูลฐานแปด" ใช้ไฟล์หรือ stdin และทิ้งข้อมูลไบนารีในรูปแบบที่มนุษย์อ่านได้ เราต้องการให้ตัวเลขของเราแสดงเป็นทศนิยมที่ไม่ได้ลงชื่อ (-t u4) และไม่ต้องการให้ดัชนีที่อยู่ (-A none) -N4 ซ้ำซ้อนเนื่องจากเราใช้เวลาเพียง 4 ไบต์ แต่ก็ไม่เจ็บเช่นกัน ฉันหวังว่าสิ่งนี้จะอธิบายได้ ...
MLP

0

สำหรับผู้ที่ googled มาที่นี่:

หากคุณใช้ anacron (เดสก์ท็อปและแล็ปท็อป Ubuntu) คุณสามารถแก้ไขได้

/etc/anacrontab

และเพิ่ม

RANDOM_DELAY=XX 

โดยที่ XX คือจำนวนนาทีที่คุณต้องการชะลองานพื้นฐาน

Anacron ก็เหมือนกับ cron แต่ไม่ได้คาดหวังว่าคอมพิวเตอร์ของคุณจะเป็นแบบ 24x7 (เช่นแล็ปท็อปของเรา) และจะเรียกใช้สคริปต์ที่พลาดไปเนื่องจากระบบไม่ทำงาน


0

คุณสามารถลองใช้ตัวอย่างนี้เพื่อใช้เวลาสุ่มก่อนดำเนินการคำสั่ง:

#!/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"

0

แล้วการสร้างสคริปต์ที่เขียน crontab ใหม่ทุกวันล่ะ?

  1. อ่าน crons ปัจจุบัน (A)
  2. เลือกเวลาสุ่ม (B)
  3. เขียน crons ก่อนหน้านี้ใหม่เพิ่ม crons แบบสุ่มใหม่ (B)
  4. ตรวจสอบให้แน่ใจว่าได้เพิ่ม cron เพื่อเรียกใช้สคริปต์นี้ตั้งแต่แรก

2
อย่าหลีกเลี่ยงระบบชื่อเสียงโดยการโพสต์ความคิดเห็นเป็นคำตอบ อย่างไรก็ตามความคิดเห็นของคุณดูดีพอที่จะเป็นคำตอบได้ ฉันขอแนะนำให้ลบ " ฉันไม่มีตัวแทนเพื่อเพิ่มความคิดเห็น แต่ "
Ted Lyngmo

1
ฉันเพิ่งตรวจสอบคำตอบนี้และพลาดส่วนที่คุณถามคำถามเป็นการตอบแทนในตอนท้าย (งานเลอะเทอะในส่วนของฉัน) อย่าตั้งคำถามในคำตอบ โพสต์คำถามของคุณเองสำหรับคำถามที่คุณมี ฉันทำให้คำถามกึ่ง ๆ ของคุณกลายเป็นสิ่งที่สามารถตอบได้
Ted Lyngmo

1
รับทราบ! ขอบคุณ. คราวหน้าจะระวังให้มากขึ้นไม่มีเจตนาร้าย
mellofellow

1
ฉันแน่ใจว่าคุณไม่มีเจตนาร้ายและไม่จำเป็นต้องระวังตัวมากเกินไป คุณสรุปวิธีแก้ปัญหาที่เป็นไปได้ - และสะดุดเล็กน้อยในตอนท้าย ไม่ต้องห่วง!
Ted Lyngmo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.