วิ่ง cron ทุก ๆ 30 วินาที


313

ตกลงดังนั้นฉันมี cron ที่ฉันต้องทำงานทุก ๆ 30 วินาที

นี่คือสิ่งที่ฉันมี:

*/30 * * * * /bin/bash -l -c 'cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'''

มันทำงานได้ แต่จะทำงานทุก 30 นาทีหรือ 30 วินาทีหรือไม่

นอกจากนี้ฉันได้อ่านแล้วว่า cron อาจไม่ใช่เครื่องมือที่ดีที่สุดที่จะใช้ถ้าฉันเรียกใช้บ่อยๆ มีอีกเครื่องมือที่ดีกว่าที่ฉันสามารถใช้หรือติดตั้งบน Ubuntu 11.04 ที่จะเป็นตัวเลือกที่ดีกว่า มีวิธีแก้ไข cron ข้างต้นหรือไม่


CommaToast และจะเกิดอะไรขึ้นหาก Javascript หรือแอป Java ของคุณล้มเหลวด้วยเหตุผลบางประการและออกไป จะเริ่มใหม่ได้อย่างไร :-)
paxdiablo

12
เพิ่มแอป NodeJS เล็กน้อย lol ทำไมไม่เป็นแอป c ++ เล็ก ๆ น้อย ๆ ? ในขณะที่เราอยู่ที่นี่เราสามารถตั้งชื่อมันว่า "cron" และเรียกใช้เป็นบริการ
Andrew


ฉันเพิ่งพบสิ่งนี้ในขณะที่ดูโปรไฟล์ผู้ใช้และเห็นว่าคุณออนไลน์น้อยกว่า 1 ชั่วโมงที่ผ่านมา (เพื่อตรวจสอบว่า ACC ยังใช้งานอยู่) มีเหตุผลใดที่คุณไม่ยอมรับคำตอบด้านล่างหรือไม่?
เฟเบียนเอ็น

คำตอบ:


731

คุณมี*/30ตัวระบุนาที - นั่นหมายถึงทุกนาที แต่ด้วยขั้นตอนที่ 30 (กล่าวคือทุกครึ่งชั่วโมง) เนื่องจากcronไม่ได้ไปที่ความละเอียดช่วงเวลาย่อยคุณจะต้องหาวิธีอื่น

ความเป็นไปได้ทางหนึ่งถึงแม้ว่ามันจะเป็น kludge (a)แต่ก็มีสองงาน แต่หนึ่งออฟเซ็ตภายใน 30 วินาที:

# Need these to run on 30-sec boundaries, keep commands in sync.
* * * * *              /path/to/executable param1 param2
* * * * * ( sleep 30 ; /path/to/executable param1 param2 )

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

ทั้งcronงานที่ทำงานจริงทุกนาที แต่หลังหนึ่งจะรอครึ่งนาทีก่อนที่จะดำเนินการ "เนื้อ" /path/to/executableของงาน

อื่น ๆ (ไม่ใช่cronชั่น) ตัวเลือกให้ดูคำตอบอื่น ๆ ที่นี่โดยเฉพาะอย่างยิ่งคนที่กล่าวขวัญและfcron systemdสิ่งเหล่านี้น่าจะดีกว่าถ้าสมมติว่าระบบของคุณมีความสามารถในการใช้ (เช่นติดตั้งfcronหรือมี distro systemdภายใน)


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

#!/bin/env bash

# Debug code to start on minute boundary and to
# gradually increase maximum payload duration to
# see what happens when the payload exceeds 30 seconds.

((maxtime = 20))
while [[ "$(date +%S)" != "00" ]]; do true; done

while true; do
    # Start a background timer BEFORE the payload runs.

    sleep 30 &

    # Execute the payload, some random duration up to the limit.
    # Extra blank line if excess payload.

    ((delay = RANDOM % maxtime + 1))
    ((maxtime += 1))
    echo "$(date) Sleeping for ${delay} seconds (max ${maxtime})."
    [[ ${delay} -gt 30 ]] && echo
    sleep ${delay}

    # Wait for timer to finish before next cycle.

    wait
done

เคล็ดลับคือการใช้sleep 30แต่จะเริ่มในพื้นหลังก่อนที่จะโหลดข้อมูลของคุณทำงาน จากนั้นหลังจากที่บรรจุเสร็จแล้วเพียงรอให้พื้นหลังsleepเสร็จสิ้น

หากเพย์โหลดใช้เวลาไม่nกี่วินาที (ที่n <= 30) การรอหลังจากเพย์โหลดจะเป็น30 - nวินาที ถ้าจะใช้เวลามากขึ้นกว่า 30 วินาทีจากนั้นรอบถัดไปจะเลื่อนออกไปจนกว่าอัตราเสร็จสิ้น แต่อีกไม่นาน

คุณจะเห็นว่าฉันมีรหัสการแก้ปัญหาที่นั่นเพื่อเริ่มต้นในขอบเขตหนึ่งนาทีเพื่อให้เริ่มต้นได้ง่ายขึ้นในการติดตาม ฉันยังค่อยๆเพิ่มเวลาในการโหลดสูงสุดดังนั้นในที่สุดคุณก็จะเห็นว่าส่วนของข้อมูลนั้นเกินกว่ารอบเวลา 30 วินาที (บรรทัดว่างพิเศษจะถูกส่งออกเพื่อให้เห็นผลได้ชัดเจน)

ตัวอย่างวิ่งดังนี้ (โดยปกติวงจรเริ่มต้น 30 วินาทีหลังจากรอบก่อนหน้า):

Tue May 26 20:56:00 AWST 2020 Sleeping for 9 seconds (max 21).
Tue May 26 20:56:30 AWST 2020 Sleeping for 19 seconds (max 22).
Tue May 26 20:57:00 AWST 2020 Sleeping for 9 seconds (max 23).
Tue May 26 20:57:30 AWST 2020 Sleeping for 7 seconds (max 24).
Tue May 26 20:58:00 AWST 2020 Sleeping for 2 seconds (max 25).
Tue May 26 20:58:30 AWST 2020 Sleeping for 8 seconds (max 26).
Tue May 26 20:59:00 AWST 2020 Sleeping for 20 seconds (max 27).
Tue May 26 20:59:30 AWST 2020 Sleeping for 25 seconds (max 28).
Tue May 26 21:00:00 AWST 2020 Sleeping for 5 seconds (max 29).
Tue May 26 21:00:30 AWST 2020 Sleeping for 6 seconds (max 30).
Tue May 26 21:01:00 AWST 2020 Sleeping for 27 seconds (max 31).
Tue May 26 21:01:30 AWST 2020 Sleeping for 25 seconds (max 32).
Tue May 26 21:02:00 AWST 2020 Sleeping for 15 seconds (max 33).
Tue May 26 21:02:30 AWST 2020 Sleeping for 10 seconds (max 34).
Tue May 26 21:03:00 AWST 2020 Sleeping for 5 seconds (max 35).
Tue May 26 21:03:30 AWST 2020 Sleeping for 35 seconds (max 36).

Tue May 26 21:04:05 AWST 2020 Sleeping for 2 seconds (max 37).
Tue May 26 21:04:35 AWST 2020 Sleeping for 20 seconds (max 38).
Tue May 26 21:05:05 AWST 2020 Sleeping for 22 seconds (max 39).
Tue May 26 21:05:35 AWST 2020 Sleeping for 18 seconds (max 40).
Tue May 26 21:06:05 AWST 2020 Sleeping for 33 seconds (max 41).

Tue May 26 21:06:38 AWST 2020 Sleeping for 31 seconds (max 42).

Tue May 26 21:07:09 AWST 2020 Sleeping for 6 seconds (max 43).

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


(a)เพื่อนร่วมงานของฉันบางคนจะบอกว่า kludges เป็นพิเศษของฉัน :-)


29
นี่เป็นวิธีแก้ปัญหาที่ดีมากดังนั้นฉันจึงคิดว่ามันจะเกินความไร้สาระ
Question Mark

14
@ rubo77 เฉพาะในกรณีที่ใช้เวลาน้อยกว่าหนึ่งวินาทีในการทำงาน :-) หากใช้เวลา 29 วินาทีมันจะเกิดขึ้นในเวลา 0:00:00, 0: 00.59, 0:01:00, 0:01:59 และอื่น ๆ .
paxdiablo

1
สุดยอดความคิดสร้างสรรค์มาก!
K Raphael

2
อะไรคือเครื่องหมายวงเล็บรอบสำหรับบรรทัดที่สอง?
Nigel Alderton

2
นี่เป็นวิธีแก้ปัญหาที่น่าทึ่งสำหรับปัญหาที่มิฉะนั้นประสิทธิภาพ crons ของ crons สำหรับงานบางอย่างที่ต้องการการดำเนินการในเวลาไม่กี่นาที ขอบคุณ.
Fiddy Bux

67

คุณทำไม่ได้ Cron มีความละเอียด 60 วินาที

* * * * * cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''
* * * * * sleep 30 && cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''

ไวยากรณ์นี้เทียบเท่ากับ paxdiablo หรือไม่ หรือมีความแตกต่างที่ลึกซึ้ง?
Nicolas Raoul

ความแตกต่างคือ: ฉันใช้เส้นทางเดิมไปยังไบนารี @paxdiablo ใช้ meta-syntax (และเรียกใช้ sub-shell)
wildplasser

1
ฉันหมายถึงใช้แทน&& ( ; )
Nicolas Raoul

2
ขอโทษ ไม่มีความแตกต่าง; &&ประกอบสั้นวงจรเพื่อให้คำสั่งต่อไปในห่วงโซ่จะไม่ทำงานถ้าหนึ่งก่อนหน้านี้ล้มเหลว
ทำลายป่า

ความละเอียดนี้ไม่ควรเป็นปัญหาสำหรับการแก้ปัญหาในนาทีย่อย
juan Isaza

37

ความละเอียดของ Cron นั้นใช้เวลาเพียงไม่กี่นาทีและไม่ได้ถูกออกแบบมาเพื่อให้ทำงานทุก ๆxวินาที รันภารกิจการทำซ้ำภายในลูปและควรทำสิ่งที่คุณต้องการ:

#!/bin/env bash
while [ true ]; do
 sleep 30
 # do what you need to here
done

54
เก็บไว้ในใจที่ไม่ได้ค่อนข้างเดียวกัน หากงานใช้เวลา 25 วินาที (ตัวอย่าง) งานจะเริ่มทุก ๆ 55 วินาทีแทนที่จะเป็นทุก ๆ 30 วินาที มันอาจไม่สำคัญ แต่คุณควรตระหนักถึงผลกระทบที่อาจเกิดขึ้น
paxdiablo

7
คุณสามารถเรียกใช้งานในพื้นหลังจากนั้นมันจะทำงานในเกือบ 30 วินาที
Chris Koston

1
ในขณะที่ [จริง] นอนหลับ 30 # ทำสิ่งที่คุณต้องทำที่นี่ --------- ควรเป็นกรณีเล็ก ๆ
วิหาร

1
จะไม่while [ true ]ทำให้คุณมีจำนวนมากกรณีของสคริปต์เดียวกันตั้งแต่ cron จะเริ่มต้นใหม่ทุกนาที?
Carcamano

2
คุณสามารถทำsleep $remainingTimeที่ที่เหลือเวลาคือ 30 ลบเวลาที่งานใช้ (และกำหนดให้เป็นศูนย์ถ้าใช้เวลา> 30 วินาที) ดังนั้นคุณต้องใช้เวลาก่อนและหลังการทำงานจริงและคำนวณความแตกต่าง
mahemoff

32

หากคุณใช้งานระบบปฏิบัติการ Linux ล่าสุดด้วย SystemD คุณสามารถใช้หน่วย SystemD Timer เพื่อเรียกใช้สคริปต์ของคุณในระดับความละเอียดใด ๆ ที่คุณต้องการ (ในทางทฤษฎีจนถึงนาโนวินาที) และ - หากคุณต้องการ - กฎการเปิดตัวที่ยืดหยุ่นกว่า Cron . ไม่sleepต้องใช้กากตะกอน

การตั้งค่ามากกว่าหนึ่งบรรทัดในไฟล์ cron นั้นใช้เวลาเล็กน้อย แต่ถ้าคุณต้องการอะไรที่ดีกว่า "ทุก ๆ นาที" มันก็คุ้มค่ากับความพยายาม

รูปแบบการจับเวลา SystemD เป็นพื้นนี้: ตัวนับเป็นหน่วยที่เริ่มต้นหน่วยบริการเมื่อมีการจับเวลาผ่านไป

ดังนั้นสำหรับทุกสคริปต์ / คำสั่งที่คุณต้องการกำหนดเวลาคุณต้องมีหน่วยบริการและจากนั้นเป็นหน่วยตัวจับเวลาเพิ่มเติม หน่วยตัวจับเวลาเดี่ยวสามารถรวมหลายตารางได้ดังนั้นโดยปกติคุณจะไม่ต้องการตัวจับเวลามากกว่าหนึ่งตัวและบริการเดียว

นี่คือตัวอย่างง่ายๆที่บันทึก "Hello World" ทุก 10 วินาที:

/etc/systemd/system/helloworld.service:

[Unit]
Description=Say Hello
[Service]
ExecStart=/usr/bin/logger -i Hello World

/etc/systemd/system/helloworld.timer:

[Unit]
Description=Say Hello every 10 seconds
[Timer]
OnBootSec=10
OnUnitActiveSec=10
AccuracySec=1ms
[Install]
WantedBy=timers.target

หลังจากตั้งค่าหน่วยเหล่านี้ (ใน/etc/systemd/systemตามที่อธิบายไว้ข้างต้นสำหรับการตั้งค่าทั้งระบบหรือที่~/.config/systemd/userการตั้งค่าเฉพาะผู้ใช้) คุณจะต้องเปิดใช้งานตัวจับเวลา (ไม่ใช่บริการแม้ว่า) โดยการเรียกใช้systemctl enable --now helloworld.timer( --nowธงยังเริ่มจับเวลา ทันทีมิฉะนั้นจะเริ่มหลังจากบูตครั้งถัดไปหรือเข้าสู่ระบบของผู้ใช้)

[Timer]สาขาส่วนใช้ที่นี่มีรายละเอียดดังนี้

  • OnBootSec - เริ่มบริการนี้หลายวินาทีหลังจากบู๊ตแต่ละครั้ง
  • OnUnitActiveSec- เริ่มบริการนี้หลายวินาทีหลังจากครั้งสุดท้ายที่เริ่มให้บริการ นี่คือสิ่งที่ทำให้ตัวจับเวลาทำซ้ำตัวเองและทำงานเหมือนงาน cron
  • AccuracySec- ตั้งค่าความแม่นยำของตัวจับเวลา ตัวจับเวลามีความแม่นยำเท่ากับที่ชุดข้อมูลนี้ตั้งไว้และค่าเริ่มต้นคือ 1 นาที (จำลอง cron) เหตุผลหลักที่ไม่ต้องการความแม่นยำที่ดีที่สุดคือการปรับปรุงการใช้พลังงาน - ถ้า SystemD สามารถกำหนดเวลาการทำงานครั้งต่อไปให้ตรงกับเหตุการณ์อื่น ๆ ได้ก็ต้องปลุก CPU ให้น้อยลง 1msในตัวอย่างข้างต้นไม่เหมาะ - ฉันมักจะตั้งค่าความถูกต้องเพื่อ1(1 วินาที) ในงานย่อยนาทีที่กำหนดของฉัน แต่ที่จะหมายถึงว่าถ้าคุณมองไปที่บันทึกการแสดง "Hello World" ข้อความคุณจะเห็นว่า มันมักจะล่าช้าประมาณ 1 วินาที หากคุณตกลงกับสิ่งนั้นฉันขอแนะนำให้ตั้งค่าความแม่นยำเป็น 1 วินาทีขึ้นไป

ดังที่คุณอาจสังเกตเห็นว่าตัวจับเวลานี้ไม่ได้เลียนแบบ Cron ทั้งหมดที่ดี - ในแง่ที่ว่าคำสั่งไม่เริ่มต้นที่จุดเริ่มต้นของทุกช่วงเวลาของนาฬิกาแขวนผนัง (กล่าวคือมันไม่ได้เริ่มในวินาทีที่ 10 จากนั้นวันที่ 20 เป็นต้นไป) แต่จะเกิดขึ้นเมื่อตัวจับเวลาหมดลง หากระบบบูตที่ 12:05:37 ดังนั้นครั้งต่อไปที่คำสั่งจะทำงานที่ 12:05:47 จากนั้นเวลา 12:05:57 เป็นต้นหากคุณสนใจความแม่นยำของนาฬิกาแขวนผนังจริงคุณก็สามารถ ต้องการแทนที่OnBootSecและOnUnitActiveSecสาขาและแทนที่จะตั้งOnCalendarกฎกับตารางเวลาที่คุณต้องการ (ซึ่งเท่าที่ผมเข้าใจไม่สามารถจะเร็วกว่า 1 วินาทีโดยใช้รูปแบบปฏิทิน) ตัวอย่างข้างต้นสามารถเขียนเป็น:

OnCalendar=*-*-* *:*:00,10,20,30,40,50

บันทึกล่าสุด: ตามที่คุณคาดเดาhelloworld.timerหน่วยจะเริ่มต้นhelloworld.serviceหน่วยเนื่องจากมีชื่อเหมือนกัน (ลบด้วยคำต่อท้ายประเภทหน่วย) นี่เป็นค่าเริ่มต้น แต่คุณสามารถแทนที่ได้โดยการตั้งค่าUnitฟิลด์สำหรับ[Timer]ส่วน

รายละเอียดเลือดเต็มสามารถดูได้ที่:


2
ฉันมักจะเจอคำตอบที่ดีกว่าเช่นนี้ในส่วนความเห็น IMHO แม้ว่า cron ได้รับการเย็บเล่มสำหรับงานที่กำหนดไว้แล้วคำตอบนี้ควรเป็นคำตอบที่ยอมรับได้เนื่องจากไม่ใช่ "งานแฮ็ก" ของ sleeps และการเสี่ยงต่อการขนานของการดำเนินงานระยะยาวโดยพิจารณาช่วงเวลา / ความถี่ที่ต้องการ
Qiqo

2
คำตอบที่ดีควรเป็นคำตอบที่เลือก
GuidedHacking

21

ไม่จำเป็นสำหรับสองรายการ cron คุณสามารถใส่ลงในรายการด้วย:

* * * * * /bin/bash -l -c "/path/to/executable; sleep 30 ; /path/to/executable"

ดังนั้นในกรณีของคุณ:

* * * * * /bin/bash -l -c "cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'' ; sleep 30 ; cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''"


11
หมายเหตุ: สิ่งนี้จะทำงานได้อย่างถูกต้องหากสคริปต์ใช้เวลาน้อยกว่าหนึ่งวินาทีในการรัน
rubo77

2
Rubo - หากงานใช้เวลาไม่กี่วินาที (แทนมิลลิวินาทีหรือไมโครวินาที) ให้เสร็จสมบูรณ์คุณจะไม่เรียกใช้ทุก ๆ สามสิบวินาทีเพื่อให้สามารถทำงานได้สองครั้งต่อนาที ใช่เริ่มต้นด้วย 30 จากนั้นลบจำนวนวินาทีต่อการวิ่งโดยประมาณถ้ามากกว่า 1 วินาที
แอนดรู

2
สิ่งนี้ไม่ได้ช่วยถ้าคุณต้องการได้รับรายงานข้อผิดพลาดสำหรับการวิ่งแต่ละครั้ง
joeln

joelin - คำสั่งที่ฉันให้ไม่ป้องกันการบันทึกข้อมูลหรือเอาท์พุทฉันทำให้คำสั่งง่ายขึ้นเพื่อตอบคำถาม หากต้องการบันทึกการบันทึกแต่ละคำสั่งสามารถ / ควรมีการเปลี่ยนเส้นทางเอาต์พุตหากคุณต้องการการบันทึกเช่นสคริปต์ / รางวิ่ง - การผลิต '\' 'Song.insert_latest' \ '' สามารถเขียนเป็นสคริปต์ / รางวิ่ง -e ผลิต '\' 'Song.insert_latest' \ '' 2> & 1> / path_to_logfile และสามารถทำได้อีกครั้งสำหรับแต่ละคำสั่งภายในรายการ cron เดียว
Andrew

13

คุณสามารถตรวจสอบคำตอบของฉันสำหรับคำถามที่คล้ายกันนี้

โดยทั่วไปฉันได้รวมสคริปต์ทุบตีชื่อ "runEvery.sh" ซึ่งคุณสามารถรันด้วย cron ทุก ๆ 1 นาทีและส่งผ่านเป็นอาร์กิวเมนต์คำสั่งจริงที่คุณต้องการเรียกใช้และความถี่เป็นวินาทีที่คุณต้องการเรียกใช้

อะไรแบบนี้

* * * * * ~/bin/runEvery.sh 5 myScript.sh


10

ใช้นาฬิกา:

$ watch --interval .30 script_to_run_every_30_sec.sh

ฉันสามารถใช้สิ่งที่ชอบได้$ watch --interval .10 php some_file.phpไหม หรือใช้watchงานได้กับไฟล์. sh เท่านั้น
Yevhenii Shashkov

คุณสามารถรันอะไรก็ได้ด้วยการดู อย่างไรก็ตามช่วงเวลาอยู่ระหว่างสิ้นสุดและเริ่มต้นของคำสั่งถัดไปดังนั้น--interval .30จะไม่ทำงานสองครั้งต่อนาที watch -n 2 "sleep 1 && date +%s"นั่นคือมันจะเพิ่มขึ้นทุก 3 วินาที
jmartori

โปรดทราบว่าwatchมันถูกออกแบบมาสำหรับการใช้งานของเครื่องปลายทาง - ในขณะที่มันสามารถทำงานได้โดยไม่ต้องใช้เครื่อง (ทำงานด้วยการnohupออกจากระบบแล้ว) หรือกับเครื่องที่ปลอม (เช่นscreen) - มันไม่มีค่าใช้จ่ายสำหรับพฤติกรรมเหมือน cron เช่นการกู้คืนจากความล้มเหลว เริ่มต้นใหม่หลังจากบู๊ต ฯลฯ '
Guss

9

งาน Cron ไม่สามารถใช้เพื่อกำหนดเวลางานในช่วงเวลาไม่กี่วินาที เช่นคุณไม่สามารถกำหนดเวลางาน cron ให้ทำงานได้ทุก 5 วินาที ทางเลือกคือการเขียนเชลล์สคริปต์ที่ใช้sleep 5คำสั่งในนั้น

สร้างเชลล์สคริปต์ every-5-seconds.sh โดยใช้ bash ในขณะที่วนซ้ำตามที่แสดงด้านล่าง

$ cat every-5-seconds.sh
#!/bin/bash
while true
do
 /home/ramesh/backup.sh
 sleep 5
done

ตอนนี้รันเชลล์สคริปต์นี้ในพื้นหลังโดยใช้nohupดังที่แสดงด้านล่าง การดำเนินการนี้จะทำให้สคริปต์ทำงานต่อไปแม้หลังจากที่คุณออกจากระบบแล้ว สิ่งนี้จะดำเนินการเชลล์สคริปต์ backup.sh ของคุณทุก 5 วินาที

$ nohup ./every-5-seconds.sh &

4
เวลาจะลอย ตัวอย่างเช่นหากbackup.shใช้เวลา 1.5 วินาทีในการรันมันจะดำเนินการทุก ๆ 6.5 วินาที มีหลายวิธีที่จะหลีกเลี่ยงสิ่งนั้นได้เช่นsleep $((5 - $(date +%s) % 5))
Keith Thompson

ฉันใหม่สำหรับ nohup ในขณะที่เรียกใช้งานตัวอย่างของคุณ nohup จะส่งคืน 'ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว' หลังจากการค้นหาบางอย่างดูเหมือนว่าคุณจะพลาด 'sh' หลังจาก nohup เช่นนี้: $ nohup sh ./every-5-seconds.sh &
VHanded

6

ใช้ fcron ( http://fcron.free.fr/ ) - ให้ความละเอียดในเวลาไม่กี่วินาทีและมีคุณสมบัติที่ดีกว่าและรวยกว่า cron (vixie-cron) และมั่นคงเช่นกัน ฉันเคยทำสิ่งที่โง่เช่นมีสคริปต์ php ประมาณ 60 ตัววิ่งบนเครื่องเดียวในการตั้งค่าที่โง่มากและมันก็ยังทำงานได้!


1
คำสารภาพของนักพัฒนา PHP )
Eric Kigathi

3
อันที่จริงแล้วคำสารภาพของวิศวกรระบบทำให้นักพัฒนา PHP .... :)
Adi Chiru

6

ใน dir /etc/cron.d/

ใหม่สร้างไฟล์ excute_per_30s

* * * * * yourusername  /bin/date >> /home/yourusername/temp/date.txt
* * * * * yourusername sleep 30; /bin/date >> /home/yourusername/temp/date.txt

จะเรียกใช้ cron ทุก ๆ 30 วินาที


4

ปัจจุบันฉันใช้วิธีการด้านล่าง ทำงานได้โดยไม่มีปัญหา

* * * * * /bin/bash -c ' for i in {1..X}; do YOUR_COMMANDS ; sleep Y ; done '

หากคุณต้องการที่จะทำงานทุกNวินาทีแล้วXจะเป็น60 / NและYจะไม่มี

ขอบคุณ.


คุณอาจต้องการเปลี่ยนYOUR_COMMANDSเพื่อYOUR_COMMANDS &ให้คำสั่งถูกเรียกใช้เป็นพื้นหลังมิฉะนั้นหากคำสั่งใช้เวลามากกว่าเศษเสี้ยวของวินาที - มันจะชะลอการเปิดใช้งานครั้งต่อไป ดังนั้นด้วย X = 2 และ Y = 30 หากคำสั่งใช้เวลา 10 วินาที - มันจะเปิดในนาทีและ 40 วินาทีต่อมาแทน 30. Kudus ถึง @paxdiablo
Guss

ด้วยเหตุผลบางอย่างถ้าฉันละเว้น/bin/bash -cส่วน (รวมถึงเครื่องหมายคำพูดอาร์กิวเมนต์) สคริปต์จะทำงานทุกนาทีโดยไม่สนใจการทำซ้ำ (ในกรณีของฉันX=12และY=5)
abiyi

3

งาน Crontab สามารถใช้เพื่อกำหนดตารางเวลางานเป็นนาที / ชั่วโมง / วัน แต่ไม่ใช่ในวินาที ทางเลือก:

สร้างสคริปต์เพื่อดำเนินการทุก ๆ 30 วินาที:

#!/bin/bash
# 30sec.sh

for COUNT in `seq 29` ; do
  cp /application/tmp/* /home/test
  sleep 30
done

ใช้crontab -eและ crontab เพื่อรันสคริปต์นี้:

* * * * * /home/test/30sec.sh > /dev/null

2
หากฉันเข้าใจอย่างถูกต้องสคริปต์นี้จะทำงาน 30 ครั้งและรอ 30 วินาทีระหว่างการทำซ้ำทุกครั้ง มันสมเหตุสมผลแล้วหรือยังที่จะทำงานทุก ๆ นาทีใน cron?
FuzzyAmi

2

คุณสามารถเรียกใช้สคริปต์นั้นเป็นบริการรีสตาร์ททุก ๆ 30 วินาที

ลงทะเบียนบริการ

sudo vim /etc/systemd/system/YOUR_SERVICE_NAME.service

วางในคำสั่งด้านล่าง

Description=GIVE_YOUR_SERVICE_A_DESCRIPTION

Wants=network.target
After=syslog.target network-online.target

[Service]
Type=simple
ExecStart=YOUR_COMMAND_HERE
Restart=always
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target

บริการโหลดซ้ำ

sudo systemctl daemon-reload

เปิดใช้งานบริการ

sudo systemctl enable YOUR_SERVICE_NAME

เริ่มบริการ

sudo systemctl start YOUR_SERVICE_NAME

ตรวจสอบสถานะบริการของคุณ

systemctl status YOUR_SERVICE_NAME

1

ขอบคุณสำหรับคำตอบที่ดีทั้งหมด เพื่อให้ง่ายฉันชอบโซลูชันที่หลากหลายด้วยการควบคุมบน crontab และการแบ่งเวลาในสคริปต์ นี่คือสิ่งที่ฉันทำเพื่อรันสคริปต์ทุก ๆ 20 วินาที (สามครั้งต่อนาที) บรรทัด Crontab:

 * * * * 1-6 ./a/b/checkAgendaScript >> /home/a/b/cronlogs/checkAgenda.log

สคริปต์:

cd /home/a/b/checkAgenda

java -jar checkAgenda.jar
sleep 20
java -jar checkAgenda.jar 
sleep 20
java -jar checkAgenda.jar 

1-6 หมายถึงอะไร
Phantom007

@ Phantom007 1-6 หมายถึงวันจันทร์ถึงวันเสาร์โดยที่ "-" เป็นช่วงและ "0" คือวันอาทิตย์ นี่คือลิงค์ที่ดีที่อธิบายฟิลด์ทั้งหมดได้ดีมากและคุณสามารถทดสอบได้ที่: " crontab.guru/# * _ * _ * _ * _ 1-6"
jfajunior

1

เขียนเชลล์สคริปต์หนึ่งไฟล์สร้างไฟล์. sh

นาโนทุก ๆ 30 วินาที

และเขียนสคริปต์

#!/bin/bash
For  (( i=1; i <= 2; i++ ))
do
    write Command here
    sleep 30
done

จากนั้นตั้งค่า cron สำหรับสคริปต์นี้ crontab -e

(* * * * * /home/username/every30second.sh)

ไฟล์ cron นี้เรียก. sh ในทุกๆ 1 นาที & ในคำสั่งไฟล์. sh จะรัน 2 ครั้งใน 1 นาที

หากคุณต้องการรันสคริปต์เป็นเวลา 5 วินาทีจากนั้นแทนที่ 30 ด้วย 5 และเปลี่ยนลูปดังนี้: For (( i=1; i <= 12; i++ ))

เมื่อคุณเลือกวินาทีใด ๆ แล้วคำนวณ 60 / วินาทีของคุณแล้วเขียนใน For loop


0

ฉันเพิ่งมีงานที่คล้ายกันให้ทำและใช้วิธีการต่อไปนี้:

nohup watch -n30 "kill -3 NODE_PID" &

ฉันจำเป็นต้องมีการฆ่าเป็นระยะ -3 (เพื่อรับการติดตามสแต็กของโปรแกรม) ทุก ๆ 30 วินาทีเป็นเวลาหลายชั่วโมง

nohup ... & 

นี่คือที่นี่เพื่อให้แน่ใจว่าฉันจะไม่สูญเสียการทำงานของนาฬิกาถ้าฉันปล่อยเปลือก (ปัญหาเครือข่าย, windows crash ฯลฯ ... )


0

ดูcron บ่อย ๆ - มันเก่า แต่เสถียรมากและคุณสามารถก้าวลงไปเป็นไมโครวินาที ณ เวลานี้สิ่งเดียวที่ฉันจะพูดกับมันก็คือฉันยังคงพยายามหาวิธีติดตั้งนอก init.d แต่เป็นบริการ systemd ดั้งเดิม แต่แน่นอนจนถึง Ubuntu 18 มันใช้งานได้เพียง ยังคงใช้ init.d (ระยะทางอาจแตกต่างกันไปตามรุ่นหลัง) มันมีข้อดีเพิ่มเติม (?) ในการตรวจสอบให้แน่ใจว่าจะไม่วางไข่ตัวอย่างของสคริปต์ PHP อื่นเว้นแต่ว่าก่อนหน้านี้จะเสร็จสมบูรณ์ซึ่งจะช่วยลดปัญหาการรั่วไหลของหน่วยความจำ


-1

ทำงานในวงเชลล์ตัวอย่าง:

#!/bin/sh    
counter=1
while true ; do
 echo $counter
 counter=$((counter+1))
 if [[ "$counter" -eq 60 ]]; then
  counter=0
 fi
 wget -q http://localhost/tool/heartbeat/ -O - > /dev/null 2>&1 &
 sleep 1
done

แม้สมมติว่า60ควรจะเป็น30คุณอาจต้องการที่จะย้ายที่wget อยู่ภายในifคำสั่งเป็นอย่างอื่นก็ดำเนินการทุกวินาที ในกรณีใด ๆ ผมไม่แน่ใจว่าวิธีการนี้คือการใด ๆ sleep 30ที่ดีกว่าเพียงแค่คนเดียว หากคุณกำลังตรวจสอบเวลา UNIX จริงมากกว่าตัวนับของคุณมันจะสร้างความแตกต่าง
paxdiablo

echo ตัวนับพิมพ์ออกคุณสามารถค้นหาเวลาที่ล่าช้าโดยคำสั่ง EXCUTE ถ้าไม่เรียกใช้ wget ในพื้นหลัง
Lo Vega
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.