วิธีการเริ่มต้นสคริปต์ Python ใหม่โดยอัตโนมัติหากมีการฆ่าหรือตาย


31

ฉันกำลังเรียกใช้สคริปต์ Python ของฉันในพื้นหลังในเครื่อง Ubuntu ของฉัน (12.04) เช่นนี้ -

nohup python testing.py > test.out &

ตอนนี้อาจเป็นไปได้ว่าในบางช่วงของฉันข้างต้นPython scriptสามารถตายด้วยเหตุผลใดก็ตาม

ดังนั้นฉันคิดว่าจะมีcron agentสคริปต์เชลล์ bash ซึ่งสามารถรีสตาร์ทสคริปต์ Python ด้านบนของฉันโดยอัตโนมัติหากมันถูกฆ่าด้วยเหตุผลใดก็ตาม

เป็นไปได้ที่จะทำ? ถ้าใช่แล้ววิธีที่ดีที่สุดในการแก้ไขปัญหาเหล่านี้คืออะไร

UPDATE:

หลังจากสร้างtesting.confไฟล์แบบนี้ -

chdir /tekooz
exec python testing.py
respawn

ฉันรันคำสั่ง sudo ด้านล่างเพื่อเริ่มต้น แต่ฉันไม่เห็นว่ากระบวนการทำงานโดยใช้ ps ax หรือไม่

root@bx13:/bezook# sudo start testing
testing start/running, process 27794
root@bx13:/bezook# ps ax | grep testing.py
27806 pts/3    S+     0:00 grep --color=auto testing.py

ความคิดใดที่ว่าทำไมขวาน px ไม่แสดงอะไรเลย? และฉันจะตรวจสอบว่าโปรแกรมของฉันทำงานหรือไม่?

นี่คือสคริปต์หลามของฉัน -

#!/usr/bin/python
while True:
    print "Hello World"
    time.sleep(5)

คำตอบ:


24

บน Ubuntu (จนถึง 14.04, 16.04 และต่อมาใช้ systemd) สามารถใช้ upstart เพื่อทำได้ดีกว่างาน cron คุณใส่การตั้งค่าใน/etc/initและให้แน่ใจว่าคุณระบุrespawn

อาจเป็นไฟล์ขั้นต่ำ/etc/init/testing.conf(แก้ไขเป็นroot):

chdir /your/base/directory
exec python testing.py
respawn

และคุณสามารถทดสอบด้วย/your/base/directory/testing.py:

from __future__ import print_function

import time

with open('/var/tmp/testing.log', 'a') as fp:
    print(time.time(), 'done', file=fp)
    time.sleep(3)

และเริ่มต้นด้วย:

sudo start testing

และติดตามสิ่งที่เกิดขึ้น (ในหน้าต่างอื่น) ด้วย:

tail -f /var/tmp/testing.log

และหยุดด้วย:

sudo stop testing

คุณยังสามารถเพิ่ม[start on][2]เพื่อให้คำสั่งเริ่มต้นเมื่อบูตระบบ


หากคุณใช้งาน cron คุณจะต้องนำไปใช้หรือค้นหารหัสสำหรับการจัดการไฟล์ PID ที่มีประสิทธิภาพ คุณต้องการให้บริการ / script / daemon ของคุณสร้างไฟล์ PID (ตั้งอยู่ภายใต้ / var / run) และให้มีการตรวจสอบรหัสเริ่มต้นว่าเนื้อหาไฟล์นั้นเก่าหรือไม่ (จากกระบวนการที่ถูกฆ่า) การเรียงลำดับของรหัสนี้เป็นเรื่องยากที่จะเขียนโดยไม่คำนึงถึงเชื้อชาติและมุมกล่อง stackoverflow.com/questions/788411/…
จิมเดนนิส

@Zelda: ขอบคุณสำหรับคำแนะนำ .. ฉันยังใหม่กับ Linux / Unix world .. การเปลี่ยนแปลงประเภทใดที่ฉันควรจะทำใน/etc/initไฟล์? หากคุณสามารถให้คำแนะนำทีละขั้นตอนสำหรับฉันแล้วฉันจะสามารถเรียนรู้บางสิ่งบางอย่างและทำสิ่งที่ถูกต้อง ..
คลังแสง

@Webby ฉันทำคำตอบที่สมบูรณ์มากขึ้น หากคุณไม่ต้องการเปิดไฟล์สำหรับเอาท์พุทและเขียนคำสั่งการพิมพ์ของคุณใหม่คุณสามารถทำสิ่งที่ชอบsys.stdout = open(file_name, 'w')ในตอนต้น
Zelda

ขอบคุณ Zelda ชื่นชมความช่วยเหลือของคุณ .. ฉันอัปเดตคำถามพร้อมรายละเอียดบางอย่าง .. ฉันพยายามทำเช่นนี้เพื่อดูว่าการทดสอบของฉันกำลังทำงานหรือไม่ .. ไม่แสดงว่ากำลังทำงานอยู่หรือไม่px ax | grep testing.py.. มันไม่ได้คืนฉันอะไรเหรอ? มีความคิดอะไรบ้าง
คลังแสง

คุณควรใส่ทุกอย่างไว้ในข้อลอง / ยกเว้นข้อและเขียนไปยังไฟล์บันทึกว่ามีข้อยกเว้นเกิดขึ้นและโปรแกรมออก อาจพิมพ์คำสั่งไม่ทำงานเนื่องจากไม่สามารถเขียนไปยัง stdout
Zelda

20

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

  1. สร้าง crontab crontab -eใหม่โดยการทำงาน นี่จะเป็นการเปิดหน้าต่างโปรแกรมแก้ไขข้อความที่คุณโปรดปราน

  2. เพิ่มบรรทัดนี้ลงในไฟล์ที่เพิ่งเปิด

    */5 * * * * pgrep -f testing.py || nohup python /home/you/scripts/testing.py > test.out
  3. บันทึกไฟล์และออกจากโปรแกรมแก้ไข

คุณเพิ่งสร้างใหม่crontabซึ่งจะทำงานทุก 5 นาทีและเปิดสคริปต์ของคุณเว้นแต่ว่ามันจะทำงานอยู่แล้ว ดูที่นี่สำหรับการกวดวิชาที่มีความสุขเล็ก ๆ cronน้อย อย่างเป็นทางการเอกสาร Ubuntu บนcronมีที่นี่

คำสั่งจริงที่กำลังทำงานอยู่คือpgrepการค้นหากระบวนการที่กำลังทำงานสำหรับสตริงที่กำหนดในบรรทัดคำสั่ง pgrep fooจะค้นหาโปรแกรมชื่อfooและผลตอบแทนของตัวบ่งชี้กระบวนการ pgrep -fทำให้มันค้นหาบรรทัดคำสั่งทั้งหมดที่ใช้ในการเปิดโปรแกรมและไม่เพียง แต่ชื่อโปรแกรม (มีประโยชน์เพราะนี่คือสคริปต์หลาม)

||สัญลักษณ์หมายถึง "ทำเช่นนี้หากคำสั่งก่อนหน้าล้มเหลว" ดังนั้นหากสคริปต์ของคุณไม่ทำงานpgrepจะล้มเหลวเนื่องจากจะไม่พบสิ่งใดเลยและสคริปต์ของคุณจะถูกเปิดใช้งาน


ขอบคุณ .. แต่ฉันยังใหม่กับ linux และ unix ดังนั้นไม่รู้ crontab ที่ไหน? นี่เป็นไฟล์ในเครื่องอูบุนตูของฉันหรือเปล่า
อาร์เซนอล

@Webby ดูคำตอบที่ปรับปรุงแล้ว
terdon

ขอบคุณ terdon .. ฉันสามารถเรียกใช้คำสั่งนี้crontab -eจากไดเรกทอรีที่สคริปต์ python ของฉัน .. ถูกต้อง?
คลังแสง

1
@Webby คุณสามารถเรียกใช้ได้จากทุกที่ที่คุณต้องการ cronคือ daemon การกำหนดเวลาเป็นบริการที่ทำงานในพื้นหลัง หากสคริปต์ python ของคุณไม่ได้อยู่ใน$PATH(ถ้าคุณไม่สามารถเรียกใช้จากที่ใดก็ได้ แต่ต้องอยู่ในไดเรกทอรีของมัน) ให้ใช้พา ธ แบบเต็มไปยังสคริปต์เหมือนในคำตอบที่อัปเดตของฉัน
terdon

ขอบคุณ ตอนนี้มันสมเหตุสมผลแล้ว .. ฉันเพิ่งสร้าง crontab ใหม่และแก้ไขไฟล์โดยเพิ่มบรรทัดเดียว แต่ 1 นาที .. ฉันได้สร้างสคริปต์ Hello World Python ที่หมุนรอบแล้วในขณะที่ True ตั้งชื่อเป็น test.py .. หลังจากบันทึก ไฟล์ crontab ควรเริ่มต้น test.py โดยอัตโนมัติหลังจาก 1 นาทีหรือไม่ และจากนั้นทำการตรวจสอบทุก ๆ 1 นาทีว่าสคริปต์ไพ ธ อนกำลังรันอยู่หรือไม่? ถ้าใช่หลังจากบันทึกไฟล์ crontab -e ฉันก็ทำ ps ax | grep test.py และฉันไม่เห็นกระบวนการใด ๆ
คลังแสง

6

คุณสามารถให้โปรแกรมทดสอบเปลี่ยนทิศทางเอาต์พุตโดยใช้ตัวเลือก commandline จากนั้นใช้สคริปต์ python แบบง่าย ๆ เพื่อเริ่มโปรแกรมใหม่โดยไม่มีกำหนด:

import subprocess

while True:
    try:
        print subprocess.check_output(['python', 'testing.py'])
    except KeyboardInterrupt:
        break

คุณสามารถวางโปรแกรมนี้ไว้ในพื้นหลังและเมื่อคุณต้องการหยุดเพียงแค่ดึงมันเข้าสู่เบื้องหน้าและฆ่ามัน


6

คุณไม่ควรใช้สิ่งนี้ในการผลิต แต่คุณสามารถ:

#!/bin/sh

while true; do
  nohup python testing.py >> test.out
done &

หากด้วยเหตุผลใดก็ตามกระบวนการของ python จะออกจากการวนรอบเชลล์จะดำเนินการต่อและเริ่มต้นใหม่ต่อท้าย.outไฟล์ตามที่ต้องการ เกือบไม่มีค่าใช้จ่ายและใช้เวลาในการตั้งค่าน้อยมาก


6

มีหลายวิธีในการตรวจสอบและกระบวนการเกิดใหม่ภายใต้ UNIX / Linux หนึ่งในรายการที่เก่าแก่ที่สุดคือรายการ "respawn" ใน / etc / inittab ... หากคุณใช้ระบบ init SysV เก่า อีกวิธีหนึ่งคือการใช้ supervisor daemon จากแพ็คเกจdaemontoolsของ DJ Bernstein ตัวเลือกอื่นคือใช้ฟีเจอร์ใน Ubuntu พุ่งพรวด ... หรือsystemdหรืออื่น ๆ

แต่คุณสามารถดูทางเลือก initและในรหัส Python สำหรับPardus: mudur daemon โดยเฉพาะ

หากคุณตัดสินใจที่จะไปกับงาน cron (และการจัดการไฟล์ PID) ให้ลองอ่านPEP 3143นี้และอาจจะใช้การอ้างอิง

ตามที่ฉันพูดถึงในความคิดเห็นอื่น ๆ การจัดการไฟล์ PID ที่มีประสิทธิภาพนั้นค่อนข้างยุ่งยาก มันมีแนวโน้มที่จะแข่งและกรณีมุม มันจะยากขึ้นหากมีโอกาสที่ไฟล์ PID ของคุณจะจบลงที่ NFS หรือระบบไฟล์เครือข่ายอื่น ๆ (อะตอมมิกส์บางตัวรับประกันว่าคุณจะได้รับความหมายของการจัดการไฟล์บนระบบไฟล์ UNIX / Linux ในท้องถิ่นที่เหมาะสมตัวอย่างเช่น). ความหมายของการล็อกไฟล์ภายใต้ระบบปฏิบัติการยูนิกซ์ก็มีความยุ่งยากเช่นกัน ( ล็อคflockหรือfcntlปล่อยออกมาทันทีในระบบปฏิบัติการเป้าหมายของคุณหรือไม่เมื่อกระบวนการที่ถือไว้ถูกฆ่าด้วย SIGKILL เป็นต้น)


3

คุณยังสามารถใช้monitหรือProcess monitoring กับ ps-watcher

Monit เป็นยูทิลิตี้แบบโอเพ่นซอร์สสำหรับการจัดการและตรวจสอบกระบวนการโปรแกรมไฟล์ไดเรกทอรีและระบบไฟล์บนระบบ UNIX Monit ดำเนินการบำรุงรักษาและซ่อมแซมอัตโนมัติและสามารถดำเนินการกับสาเหตุที่มีความหมายในสถานการณ์ที่ผิดพลาดได้

นี่คือตัวอย่างสำหรับสถานการณ์ของคุณ:

check process myprocessname
        matching "myprocessname"
        start program = "nohup /usr/bin/python /path/testing.py > /tmp/test.out &"
        stop program = "/usr/bin/killall myprocessname"

ลองดูตัวอย่าง monit


1

คุณต้องการหัวหน้างานคุณสามารถใช้หัวหน้างานได้ มันเป็นผู้ควบคุมที่ใช้ python ดังนั้นจึงง่ายต่อการปรับเปลี่ยนหากคุณต้องการ

การควบคุมอยู่กับไฟล์ที่มีไวยากรณ์ไฟล์. ini


0

คำตอบของ Terdon ไม่ได้ผลสำหรับฉันเพราะ pgrep -f testing.pyไม่เคย 'ล้มเหลว' มันจะคว้า pid สำหรับงาน cron (เพราะตัวเลือก -f) อย่างไรก็ตามหากไม่มีตัวเลือก -f pgrep จะไม่พบ test.py เพราะไม่มีกระบวนการที่เรียกว่า test.py

ทางออกของฉันคือการเปลี่ยนแปลง

pgrep -f testing.py

ไปยัง

pgrep -f testing.py | pgrep python

นี่หมายถึงงาน crontab เต็มรูปแบบจะเป็น:

*/5 * * * * pgrep -f testing.py | pgrep python || nohup python /home/you/scripts/testing.py > test.out

0

ในกรณีของฉันเป็นการแก้ไขด่วนฉันต้องการให้โปรแกรมของฉันทำงานต่อเมื่อออกจากข้อผิดพลาด en หรือถูกฆ่า ในทางกลับกันฉันต้องการหยุดการทำงานเมื่อโปรแกรมสิ้นสุดลงอย่างถูกต้อง (return code = 0)

ฉันได้ทดสอบมันกับ Bash แล้ว มันควรจะทำงานได้ดีในเปลือกอื่น ๆ

#!/bin/sh

echo ""
echo "Use: $0 ./instagram.py"
echo ""

echo "Executing $1 ..."

EXIT_CODE=1
(while [ $EXIT_CODE -gt 0 ]; do
    $1
    # loops on error code: greater-than 0
    EXIT_CODE=$?
done)

0

สำหรับคำตอบของ terdon pgrep -f testing.pyจะไม่คืนค่าเท็จตามความคิดเห็นที่นี่ :

ฉันคิดว่าปัญหาคือ cron วางไข่เชลล์เพื่อรันคำสั่งของคุณและอาร์กิวเมนต์ของเชลล์นั้นถูกจับคู่โดย pgrep เนื่องจากคุณใช้ -f

สำหรับคำตอบของ Matt pgrep -f testing.pyนั้นไม่มีประโยชน์อะไรตั้งแต่pgrep pythonจับคู่สคริปต์ Python ที่รันอยู่ ดังนั้นถ้า Python script cronjob สองตัว cronjob ที่สองจะไม่ทำงาน

แล้วฉันก็พบวิธีแก้ปัญหาpgrep -f testing.pyในความคิดเห็นที่นี่: https://askubuntu.com/questions/1014559/running-pgrep-in-a-crontab?noredirect=1&lq=1

cron ของฉันสำหรับเรียกใช้สคริปต์ Python สองสคริปต์:

* * * * * pgrep -f '^/usr/bin/python36 /home/ec2-user/myscript1\.py' || nohup /usr/bin/python36 /home/ec2-user/myscript1.py

0 * * * * pgrep -f '^/usr/bin/python36 /home/ec2-user/myscript2\.py' || nohup /usr/bin/python36 /home/ec2-user/myscript2.py
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.