Cách tự động khởi động lại tập lệnh Python nếu nó bị giết hoặc chết


31

Tôi đang chạy tập lệnh Python của mình trong nền trong máy Ubuntu (12.04) như thế này -

nohup python testing.py > test.out &

Bây giờ, có thể ở một giai đoạn nào đó, phần trên của tôi Python scriptcó thể chết vì bất kỳ lý do gì.

Vì vậy, tôi nghĩ sẽ có một số loại cron agentkịch bản bash shell có thể tự động khởi động lại tập lệnh Python ở trên nếu nó bị giết vì bất kỳ lý do gì.

Đây có phải là có thể làm gì? Nếu có, cách tốt nhất để giải quyết các loại vấn đề này là gì?

CẬP NHẬT:

Sau khi tạo testing.conftập tin như thế này -

chdir /tekooz
exec python testing.py
respawn

Tôi đã chạy bên dưới lệnh sudo để khởi động nó nhưng tôi không thể thấy quá trình đó chạy phía sau bằng cách sử dụng 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

Bất cứ ý tưởng tại sao px ax không hiển thị cho tôi bất cứ điều gì? Và làm cách nào để kiểm tra xem chương trình của tôi có chạy hay không?

Đây là kịch bản python của tôi -

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

Câu trả lời:


24

Trên Ubuntu (cho đến 14.04, 16.04 và sau đó sử dụng systemd) có thể sử dụng upstart để làm như vậy, tốt hơn so với công việc định kỳ. Bạn đặt một thiết lập cấu hình /etc/initvà đảm bảo rằng bạn chỉ định hồi sinh

Nó có thể là một tệp tối thiểu /etc/init/testing.conf(chỉnh sửa là root):

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

Và bạn có thể kiểm tra với /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)

và bắt đầu với:

sudo start testing

và theo dõi những gì xảy ra (trong một cửa sổ khác) với:

tail -f /var/tmp/testing.log

và dừng lại với:

sudo stop testing

Bạn cũng có thể thêm [start on][2]để có lệnh khởi động khi khởi động hệ thống.


Nếu bạn sử dụng một công việc định kỳ thì bạn sẽ muốn thực hiện hoặc tìm một số mã để xử lý tệp PID mạnh mẽ. Bạn muốn yêu cầu dịch vụ / script / daemon của bạn tạo một tệp PID (theo quy ước nằm dưới / var / run) và kiểm tra mã khởi động của nó nếu nội dung tệp bị cũ (do quá trình bị hủy). Loại mã này là đáng ngạc nhiên khó khăn để viết miễn phí các chủng tộc và trường hợp góc. stackoverflow.com/questions/788411/ Mạnh
Jim Dennis

@Zelda: Cảm ơn bạn đã gợi ý .. Tôi chưa quen với thế giới Linux / Unix .. Loại thay đổi nào tôi phải thực hiện trong /etc/inittệp? Nếu bạn có thể cung cấp hướng dẫn từng bước cho tôi, thì tôi sẽ có thể học được điều gì đó và làm điều đúng đắn ..
kho vũ khí

@Webby Tôi đã làm cho câu trả lời đầy đủ hơn. Nếu bạn không muốn mở một tệp cho đầu ra và viết lại các câu lệnh in của bạn, bạn có thể làm một cái gì đó như sys.stdout = open(file_name, 'w')lúc đầu.
Zelda

Cảm ơn bạn Zelda. Đánh giá cao sự giúp đỡ của bạn .. Tôi đã cập nhật câu hỏi với một số chi tiết .. Tôi đang cố gắng làm như thế này để xem thử nghiệm của tôi có chạy hay không .. Nó không cho tôi biết liệu nó có đang chạy hay không .. px ax | grep testing.py.. Nó đang trả lại cho tôi không có gì? Bất cứ ý tưởng tại sao?
kho vũ khí

Bạn nên đặt toàn bộ điều trong một mệnh đề try / trừ và ghi vào logfile những gì ngoại lệ được tạo ra và chương trình thoát ra. Có thể câu lệnh in không hoạt động vì nó không thể ghi vào thiết bị xuất chuẩn.
Zelda

20

Bạn cũng có thể có một cách tiếp cận theo hướng vỏ hơn. Hãy cronxem kịch bản của bạn và khởi chạy lại nếu nó chết.

  1. Tạo một crontab mới bằng cách chạy crontab -e. Điều này sẽ đưa ra một cửa sổ của trình soạn thảo văn bản yêu thích của bạn.

  2. Thêm dòng này vào tập tin vừa mở

    */5 * * * * pgrep -f testing.py || nohup python /home/you/scripts/testing.py > test.out
  3. Lưu tệp và thoát khỏi trình chỉnh sửa.

Bạn vừa tạo một cái mới crontabsẽ được chạy cứ sau 5 phút và khởi chạy tập lệnh của bạn trừ khi nó đang chạy. Xem ở đây để có một hướng dẫn nhỏ đẹp trên cron. Các tài liệu chính thức của Ubuntu trên cronở đây .

Lệnh thực tế đang chạy là pgreptìm kiếm các tiến trình đang chạy cho chuỗi được đưa ra trong dòng lệnh. pgrep foosẽ tìm kiếm một chương trình có tên foovà trả về định danh quy trình của nó . pgrep -flàm cho nó tìm kiếm toàn bộ dòng lệnh được sử dụng để khởi chạy chương trình và không chỉ tên chương trình (hữu ích vì đây là tập lệnh python).

Các ||phương tiện biểu tượng "làm điều này nếu các lệnh trước đó đã thất bại". Vì vậy, nếu tập lệnh của bạn không chạy, pgrepnó sẽ thất bại vì nó sẽ không tìm thấy gì và tập lệnh của bạn sẽ được khởi chạy.


Cảm ơn bạn .. Nhưng tôi chưa quen với linux và unix nên không biết crontab ở đâu? Đây có phải là một tập tin trong máy ubfox của tôi ở đâu đó không?
kho vũ khí

@Webby xem câu trả lời cập nhật.
terdon

Cảm ơn terdon .. Tôi có thể chạy lệnh này crontab -etừ thư mục chứa tập lệnh python của tôi .. Đúng không?
kho vũ khí

1
@Webby bạn có thể chạy nó từ bất cứ đâu bạn muốn. cronlà một daemon lập lịch, nó là một dịch vụ chạy trong nền. Nếu tập lệnh python của bạn không nằm trong $PATH(nếu bạn không thể khởi chạy nó từ bất kỳ đâu nhưng cần phải có trong thư mục của nó), hãy sử dụng đường dẫn đầy đủ đến tập lệnh như trong câu trả lời được cập nhật của tôi.
terdon

Cảm ơn. Bây giờ nó có ý nghĩa .. Tôi vừa tạo một crontab mới và chỉnh sửa tệp bằng cách thêm cùng một dòng nhưng trong 1 phút .. Tôi đã tạo một tập lệnh Hello World Python xoay quanh trong khi True có tên là tests.py .. Sau khi lưu tập tin crontab, nó sẽ tự động bắt đầu thử nghiệm sau 1 phút? Và sau đó tiếp tục kiểm tra cứ sau 1 phút xem kịch bản python có chạy hay không? Nếu có, sau khi lưu tệp crontab -e, tôi đã thực hiện ps ax | grep tests.py và tôi không thể thấy bất kỳ quy trình nào cho việc đó?
kho vũ khí

6

Bạn có thể yêu cầu chương trình thử nghiệm chuyển hướng đầu ra bằng tùy chọn dòng lệnh và sau đó sử dụng tập lệnh python đơn giản để khởi động lại chương trình vô thời hạn:

import subprocess

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

bạn có thể đặt chương trình này ở chế độ nền và một khi bạn muốn dừng lại, chỉ cần kéo nó vào nền trước và giết nó.


6

Bạn không nên thực sự sử dụng nó cho sản xuất, nhưng bạn có thể:

#!/bin/sh

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

Nếu vì bất kỳ lý do nào, quá trình python thoát ra, vòng lặp shell sẽ tiếp tục và khởi động lại nó, nối thêm vào .outtệp như mong muốn. Gần như không có chi phí và mất rất ít thời gian để thiết lập.


6

Có một số cách để theo dõi và hồi sinh các quy trình trong UNIX / Linux. Một trong những mục cũ nhất là mục "hồi sinh" trong / etc / inittab ... nếu bạn đang sử dụng hệ thống init SysV cũ. Một phương pháp khác là sử dụng trình nền giám sát từ gói daemontools của DJ Bernstein . Các tùy chọn khác là sử dụng các tính năng trong Ubuntu mới bắt đầu ... hoặc systemd hoặc các tính năng khác.

Nhưng bạn có thể xem xét các lựa chọn thay thế init và trong mã Python cho Pardus: Mudur daemon nói riêng.

Nếu bạn quyết định thực hiện một công việc định kỳ (và xử lý tệp PID) thì hãy xem xét việc đọc PEP 3143 này và có thể sử dụng triển khai tham chiếu của nó.

Như tôi đã đề cập trong các bình luận khác của tôi, việc xử lý tệp PID mạnh mẽ là khó khăn. Nó dễ bị các cuộc đua và trường hợp góc. Sẽ khó hơn nếu có bất kỳ cơ hội nào mà tệp PID của bạn kết thúc trên một NFS hoặc hệ thống tệp được nối mạng khác (một số nguyên tử đảm bảo bạn có được ngữ nghĩa xử lý tệp trên các hệ thống tệp UNIX / Linux cục bộ sẽ biến mất trên một số phiên bản và triển khai NFS, ví dụ). Ngoài ra, ngữ nghĩa xung quanh việc khóa tệp trong UNIX có thể khó khăn. (Chẳng hạn, một khóa flockhoặc fcntlkhóa được phát hành kịp thời, trong hệ điều hành mục tiêu của bạn, khi quá trình giữ nó bị giết bằng SIGKILL chẳng hạn?).


3

Bạn cũng có thể sử dụng theo dõi monit Hoặc Process với ps-watcher

Monit là một tiện ích nguồn mở để quản lý và giám sát, xử lý, chương trình, tệp, thư mục và hệ thống tệp trên hệ thống UNIX. Monit tiến hành bảo trì và sửa chữa tự động và có thể thực hiện các hành động nhân quả có ý nghĩa trong các tình huống lỗi.

Dưới đây là ví dụ cho kịch bản của bạn:

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

Hãy xem các ví dụ monit


1

Bạn cần một người giám sát, bạn có thể sử dụng người giám sát . Đây là trình giám sát dựa trên python, do đó dễ dàng sửa đổi nếu bạn cần.

Kiểm soát với các tệp có cú pháp tệp .ini.


0

Câu trả lời của Terdon, không hiệu quả với tôi, vì pgrep -f testing.pykhông bao giờ "thất bại". Nó sẽ lấy pid cho công việc định kỳ (vì tùy chọn -f). Tuy nhiên, nếu không có tùy chọn -f, pgrep sẽ không tìm thấy test.txt vì không có quá trình nào được gọi là tests.py.

Giải pháp của tôi cho vấn đề này là thay đổi

pgrep -f testing.py

đến

pgrep -f testing.py | pgrep python

điều này có nghĩa là công việc crontab đầy đủ sẽ là:

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

0

Trong trường hợp của tôi, như là một sửa chữa nhanh, tôi muốn giữ cho chương trình của tôi chạy khi nó thoát với lỗi en hoặc nó đã bị giết. Mặt khác, tôi muốn dừng thực thi khi chương trình kết thúc chính xác (return code = 0)

Tôi đã thử nó trên Bash. Nó sẽ hoạt động tốt trong bất kỳ vỏ nào khác

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

Đối với câu trả lời của terdon, pgrep -f testing.pysẽ không bao giờ trả lại sai theo các nhận xét ở đây :

Tôi nghĩ vấn đề là cron sinh ra một shell để chạy lệnh của bạn và các đối số của shell đó được khớp bởi pgrep vì bạn đang sử dụng -f

Đối với câu trả lời của Matt, pgrep -f testing.pylà vô ích vì pgrep pythonphù hợp với bất kỳ tập lệnh Python nào đang chạy. Vì vậy, nếu hai cronjob tập lệnh Python, cronjob thứ hai sẽ không bao giờ chạy.

Và sau đó tôi đã tìm ra giải pháp để giải quyết pgrep -f testing.pytrong bình luận ở đây: https://askubfox.com/questions/1014559/rasty-pgrep-in-a-crontab?noredirect=1&lq=1

Cron của tôi để chạy hai tập lệnh 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.