Как автоматически перезапускать скрипт python при ошибке

For something like this (connecting to a web page), it’s often better to make the upper limit based on time instead of the number of times you attempt to connect. So use a while loop instead:

import numpy as np
import time

def main():
    np.load('file.csv')

start = time.time()
stop = start + 5
attempts = 0
result = 'failed'

while True:
    if time.time()<stop:
        try:
            main()
        except Exception as e:
            attempts += 1
            print e
            time.sleep(0.1) # optional
            print 'Restarting!'
            continue
        else:
            result = 'succeeded'
    print 'Connection %s after %i attempts.' % (result, attempts)
    break

Optional: I included a 100 ms pause after each failed attempt. This can help with establishing a connection sometimes.

Then wrap the whole thing up in a function you can use in the future for other projects:

# retry.py

import time

def retry(f, seconds, pause = 0):
    start = time.time()
    stop = start + seconds
    attempts = 0
    result = 'failed'

    while True:
        if time.time()<stop:
            try:
                f()
            except Exception as e:
                attempts += 1
                print e
                time.sleep(pause)
                print 'Restarting!'
                continue
            else:
                result = 'succeeded'
        print '%s after %i attempts.' % (result, attempts)
        break

now just do this:

import numpy as np
from retry import retry

def main():
    np.load('file.csv')

retry(main, 5, 0.1)

Testing procedure:

class RetryTest():
    def __init__(self, succeed_on = 0, excp = Exception()):
        self.succeed_on = succeed_on
        self.attempts = 0
        self.excp = excp
    def __call__(self):
        self.attempts += 1
        if self.succeed_on == self.attempts:
            self.attempts = 0
        else:
            raise self.excp

retry_test1 = RetryTest(3)
retry(retry_test1, 5, 0.1)
# succeeded after 3 attempts.
retry_test2 = RetryTest()
retry(retry_test2, 5, 0.1)
# failed after 50 attempts.

I have a program that queries an API every few seconds. Each response triggers a few functions which themselves make some calls to websites and such — calls that I don’t want to blindly trust to succeed. If I catch an exception in foo(), for example, or even in a function that foo() calls, is it possible to restart the program entirely in the except block? Essentially, I want to call queryRepeatedly() upon an exception in one of its sub-functions, without keeping the previous call on the stack.

Of course, I could return marker values and solve this another way, but the program is structured in a way such that the above approach seems much simpler and cleaner.

# Sample "main" function that I want to call
def queryRepeatedly():
    while True:
        foo()
        bar()
        baz()
        time.sleep(15)

def foo():
    # do something
    try:
        foo2() # makes a urllib2 call that I don't trust
    except:
        #restart queryRepeatedly

queryRepeatedly()

pppery's user avatar

pppery

3,72723 gold badges33 silver badges46 bronze badges

asked Jul 8, 2013 at 18:02

vroomfondel's user avatar

3

To restart anything, just use a while loop outside the try. For example:

def foo():
    while True:
        try:
            foo2()
        except:
            pass
        else:
            break

And if you want to pass the exception up the chain, just do this in the outer function instead of the inner function:

def queryRepeatedly():
    while True:
        while True:
            try:
                foo()
                bar()
                baz()
            except:
                pass
            else:
                break
        time.sleep(15)

def foo():
    foo2()

All that indentation is a little hard to read, but it’s easy to refactor this:

def queryAttempt()
    foo()
    bar()
    baz()

def queryOnce():
    while True:
        try:
            queryAttempt()
        except:
            pass
        else:
            break

def queryRepeatedly():
    while True:
        queryOnce()
        time.sleep(15)

But if you think about it, you can also merge the two while loops into one. The use of continue may be a bit confusing, but see if you like it better:

def queryRepeatedly():
    while True:
        try:
            foo()
            bar()
            baz()
        except:
            continue
        time.sleep(15)

Daniel Walker's user avatar

answered Jul 8, 2013 at 18:05

abarnert's user avatar

abarnertabarnert

355k52 gold badges601 silver badges673 bronze badges

2

Refactor this — you’ll get a stackoverflow error sooner or later if you have enough failures.

queryRepeatedly should just be query. It should return void and throw exceptions on failures.

Wrap in something that looks like this, your true queryRepeatedly function?

while True:
    try:
        query()
    except:
        #handle
    time.sleep(15)

All looping, no recursion needed.

Note that you must think carefully about how much of your program you need to restart. From your question it sounded like your actual problem was ensuring the query could try again if it sporadically fails, which is what my solution ensures. But if you want to clean up program resources — say, bounce SQL connections, which may have broken — then you need to think more carefully about how much of your program you need to «restart.» In general you need to understand why your query failed to know what to fix, and in the extreme case, the right thing to do is an email or SMS to someone on call who can inspect the situation and write an appropriate patch or fix.

answered Jul 8, 2013 at 18:06

djechlin's user avatar

djechlindjechlin

59.3k35 gold badges162 silver badges291 bronze badges

12

First make two files.

One file called run.py and one called forever.py and put them in the same folder.

Go to your terminal within that folder and type chmod +x forever.py

run.py

whatever code you want to run

forever.py

#!/usr/local/lib/python3.7
from subprocess import Popen
import sys

filename = sys.argv[1]
while True:
    print("\nStarting " + filename)
    p = Popen("python3 " + filename, shell=True)
    p.wait()

Open a terminal window from the folder and type this:

python3 ./forever.py run.py

to start run.py and if it fails or has an exception, it’ll just start over again.

You now have a template to make sure if a file crashes or has an exception, you can restart it without being around. If this helps you, please give me a vote!

Olivier's user avatar

answered Mar 1, 2020 at 4:50

Cody Krecicki's user avatar

0

In your exception make a recursive call

except:
      queryRepeatedly()

answered Jul 8, 2013 at 18:06

sedavidw's user avatar

sedavidwsedavidw

11.1k13 gold badges61 silver badges95 bronze badges

4

Как сделать так чтобы скрипт на питоне при ошибке заново запускался?

Вот у меня есть телеграм бот, и иногда он стопается, мол ошибка (там другая история).
И как сделать так, чтобы скрипт автоматически после остановки запускался заново (python bot.py)?


  • Вопрос задан

  • 2429 просмотров

while true; do python bot.py; done

Можно с помощью инструкций try/except.

def function():	
	try:
		a = input("Enter a number")
		b = int(a) / 0
	except:
		function()
function()

Поместите туда свой код, при ошибке, функция будет вызвана заново.

Пригласить эксперта


  • Показать ещё
    Загружается…

22 сент. 2023, в 01:22

10000 руб./за проект

22 сент. 2023, в 00:39

30000 руб./за проект

21 сент. 2023, в 22:23

5000 руб./за проект

Минуточку внимания

Here is a simple trick that I used to restart my python script after unhandled exception.

Let’s say I have this simple script called test.py that I want to run forever. It will just wait 2 seconds and throw an error.

import time

time.sleep(2)
raise Exception("Oh oh, this script just died")
Code language: JavaScript (javascript)

I use the following script called forever in the same directory:

#!/usr/bin/python
from subprocess import Popen
import sys

filename = sys.argv[1]
while True:
    print("\nStarting " + filename)
    p = Popen("python " + filename, shell=True)
    p.wait()
Code language: JavaScript (javascript)

It uses python to open test.py as a new subprocess. It does so in an infinite while loop, and whenever test.py fails, the while loop restarts test.py as a new subprocess.

I’ll have to make the forever script executable by running chmod +x forever. Optionally forever script can be moved to some location in the PATH variable, to make it available from anywhere.

Next, I can start my program with:

./forever test.py

Which will result in the following output:

Starting test.py
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise Exception("Oh oh, this script just died")
Exception: Oh oh, this script just died

Starting test.py
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    raise Exception("Oh oh, this script just died")
Exception: Oh oh, this script just died

Starting test.pyCode language: JavaScript (javascript)

As you can tell, this script will run repeatedly, until it is killed with ctr+c.

Одной из важнейших задач при разработке серверных частей API или Ботов, обрабатывающих различные оповещения, является обеспечение их бесперебойной работы. Иными словами, необходимо автоматизированно произвести запуск всех необходимых скриптов при перезагрузке системы и перезапуск в случае ошибок и падений.

Одним из главных иструментов является supervisor.

Для установки достаточно набрать следующую команду в терминале (считаем что менеджер пакетов pip у вас уже уставнолен. Как это сделать читайте в статье Создаем бота для telegram).

sudo pip install supervisor

Супервизор позволяет следить за состоянием приложений, останавливать, запускать и перезапускать их. Для начала нам нужно создать конфигурационный файл для вашей программы, где мы опишем основные правила перезапуска и логирования. По умолчанию можно воспользоваться файлом:

/etc/supervisor/supervisord.conf

Удалим все содержимое и впишем следующий текст:

[program:github_server]
command=python server.py
directory=/var/www/codex.bot/
autorestart=true
redirect_stderr=true
stdout_logfile=/var/www/codex.bot/logs/app_sd.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=50
stdout_capture_maxbytes=1MB
stdout_events_enabled=false
loglevel=warn

В примере мы указываем, что хотим обеспечить контроль скрипта server.py, находящегося в директории /var/www/codex.bot и уточняем еще пару настроек логирования ошибок. Если супервизор у вас еще не запущен, выполните команду:

supervisord

Теперь можно попросить супервизор прочитать данные из конфига:

supervisorctl reread

Для просмотра статуса запущенных процессов воспользуйтесь командой:

supervisorctl status

Процесс под названием “github_server” (название указывается в конфиге) будет находится в состоянии “STOPPED”.

Запустим его:

supervisorctl start

Теперь в статусе будет отображено состояние “RUNNING”. Для остановки процесса можно пользоваться командой:

supervisorctl stop

Наконец, если принудительно завершить процесс:

sudo killall python

Он все равно будет перезапущен супервизором:

Состояние до завершения: github_server RUNNING pid 21755, uptime 0:03:57
Состояние после завершения: github_server RUNNING pid 21929, uptime 0:00:01

Видно, что сервер был перезапущен. Более подробно можно почитать в официальной документации.

Понравилась статья? Поделить с друзьями:
  • Как быстро исправить ошибку 0xc000007b
  • Как а также какая ошибка
  • Как было больно осознать любовь ошибкою была
  • Как бык на новые ворота фразеологизм ошибка
  • Как будто работа над ошибками