6

I run a Python Discord bot. I import some modules and have some events. Now and then, it seems like the script gets killed for some unknown reason. Maybe because of an error/exception or some connection issue maybe? I'm no Python expert but I managed to get my bot working pretty well, I just don't exactly understand how it works under the hood (since the program does nothing besides waiting for events). Either way, I'd like it to restart automatically after it stops.

I use Windows 10 and just start my program either by double-clicking on it or through pythonw.exe if I don't want the window. What would be the best approach to verify if my program is still running (it doesn't have to be instant, the verification could be done every X minutes)? I thought of using a batch file or another Python script but I have no idea how to do such thing.

Thanks for your help.

dan
  • 3,439
  • 17
  • 54
  • 82
  • Maybe you could write a script which checks every minute if your script is running and if not it restarts it? Just a quick idea. – creyD May 22 '17 at 12:05
  • @creyD Yes. How would be the best approach to do so? Should I use Python, batch or something else? If you think Python is the best approach, that will at least point me in a direction to filter my search a little bit further (since I didn't experiment much with the OS libraries in Python). – dan May 22 '17 at 12:06
  • I guess @Gahan answered your question aswell. I would write a simple batch script for the task. You can even start this script with windows so even if your system goes down it will start again. – creyD May 22 '17 at 12:09
  • would `atexit` not have been the easiest option? – WhatsThePoint May 22 '17 at 12:29
  • @WhatsThePoint I guess it depends how the script ended, which I don't exactly know right now. I think it might be when I'm having internet connection issues, maybe from the discord.py API, but I'm extremely unsure as my knowledge is pretty limited in Python. If the script is totally killed (as in, I open the task manager and kill it), I don't think atexit would work. – dan May 22 '17 at 12:49
  • possibly, the examples to when `atexit` is not called as described here https://pymotw.com/2/atexit/ probably fall in to your issue meaning `atexit` would probably be useless – WhatsThePoint May 22 '17 at 12:57
  • https://stackoverflow.com/a/33334183/1340631 has a nice solution. – scai Jan 06 '21 at 10:42

2 Answers2

10

You can write another python code (B) to call your original python code (A) using Popen from subprocess. In python code (B), ask the program to wait for your python code (A). If 'A' exits with an error code, recall it from B.

I provide an example for python_code_B.py

import subprocess

filename = 'my_python_code_A.py'
while True:
    """However, you should be careful with the '.wait()'"""
    p = subprocess.Popen('python '+filename, shell=True).wait()

    """#if your there is an error from running 'my_python_code_A.py', 
    the while loop will be repeated, 
    otherwise the program will break from the loop"""
    if p != 0:
        continue
    else:
        break

This will generally work well on Unix / Windows systems. Tested on Win7/10 with latest code update.

Also, please run python_code_B.py from a 'real terminal' which means running from a command prompt or terminal, and not in IDLE.

J0hn
  • 570
  • 4
  • 19
emmanuelsa
  • 657
  • 6
  • 9
  • Thank you, I will look further into subprocess and popen, it seems rather simple overall. – dan May 22 '17 at 12:13
  • 1
    Thank you for the edit, that's exactly what I was looking for. I was toying with https://stackoverflow.com/questions/325463/launch-a-shell-command-with-in-a-python-script-wait-for-the-termination-and-ret. – dan May 22 '17 at 12:26
  • I am very happy that my example is helpful – emmanuelsa May 22 '17 at 12:28
  • I will let it run a couple of days and see if it improves stability or not. If it does, I will improve this to manage return codes since without any verification, if I do some syntax error in my A script, the B script will try launching A hundreds of times per second. – dan May 22 '17 at 12:32
  • Also, what is the impact of running the B script from cmd.exe instead of by just launching it directly with Windows? Asking since you recommended using a terminal (I guess you meant cmd in Windows). I might want to use pythonw.exe with a scheduled task in Windows in the future instead to make it more transparent... – dan May 22 '17 at 12:32
  • I am believing that terminals have more consistent ways of handling the return codes. Indeed, I mainly use `Unix-based` systems. However, I also used this on many Windows machines in the past. It works fine on most machines. However, some `old Windows OS` do not handle programs return codes properly. – emmanuelsa May 22 '17 at 13:13
  • I have implemented this second code B and whilst it works I am just wondering if this code B will run into hang issues as well given that it uses a while infinity loop. My code A runs out of memory because of a while loop and while I think it's highly unlikely but just wanted to make sure and be clear myself. – Stanwin Siow Jan 13 '20 at 09:10
  • Cool. that's exactly what I was looking for – seralouk Feb 20 '21 at 08:59
2

for problem you stated i prefer to use python subprocess call to rerun python script or use try blocks. This might be helpful to you. check this sample try block code:

try:
  import xyz # consider it is not exist or any error code
except:
  pass # go to next line of code to execute
Gahan
  • 4,075
  • 4
  • 24
  • 44
  • Would you care to elaborate on try blocks? As in, how is the program supposed to go through try blocks if it got killed? Also, I do understand the basic syntax and can implement it, but am I supposed to add try blocks to all my events and what am I supposed to check exactly? As for subprocess, I haven't read about it yet so I'll do now, thank you. – dan May 22 '17 at 12:09
  • Or is the try block supposed to be in another program that is just used as a launcher and triggers an exception if the program stops? – dan May 22 '17 at 12:10
  • write your code in try block if it fails to execute it went to except block at which you can also write alternate code or if you want to skip it you can just write pass in that code let assume you don't have module name XYZ and if you import it normally it gives you import error but you can write it in try block as: try: import XYZ except: pass – Gahan May 22 '17 at 12:11