Several ways to auto restart python script on crash — a bash while loop, systemd, and StayPresent — with tradeoffs for each.
How to Automatically Restart a Python Script When It Crashes
A script that dies on an unhandled exception and just... stays dead is one of the most common reliability gaps in small Python projects. If you've searched for how to auto restart a python script on crash, there are a few different ways to solve it, each with real tradeoffs — from a quick shell one-liner to a properly supervised subprocess. Here's the full range of options.
Table of Contents
- Why Scripts Need Restart Logic at All
- Option 1: A Bash
whileLoop - Option 2:
try/exceptAround Your Ownmain() - Option 3: systemd
Restart=on-failure - Option 4: StayPresent's Subprocess Supervision
- Comparing the Options
- Avoiding Crash Loops
- Full Example with StayPresent
- FAQs
- Conclusion
Why Scripts Need Restart Logic at All
Python doesn't restart a crashed process on its own — once an unhandled exception propagates to the top, the interpreter exits, and nothing else happens unless something outside that process notices and relaunches it. For a script meant to run continuously (a bot, a worker, a poller), that means a single unhandled exception silently ends its uptime until a human notices and manually restarts it.
Option 1: A Bash while Loop
The simplest possible fix, often used for quick local testing:
while true; do
python bot.py
echo "Bot crashed, restarting in 2 seconds..."
sleep 2
done
Enter fullscreen mode Exit fullscreen mode
This works, but it has no restart limit — a genuine crash loop (a missing config value, a bad credential) will restart forever, silently burning resources with no ceiling. It also doesn't distinguish between a bot exiting intentionally (sys.exit(0)) and an actual crash — it restarts either way.
Option 2: try/except Around Your Own main()
import time
while True:
try:
main()
except Exception as e:
print(f"Crashed: {e}")
time.sleep(2)
Enter fullscreen mode Exit fullscreen mode
This keeps recovery inside the same process rather than relaunching a new one, which means in-memory state isn't reset between crashes. That can be useful (you don't lose everything on a transient error) or dangerous (you might restart into the exact same corrupted state that caused the crash in the first place), depending on what actually failed.
Option 3: systemd Restart=on-failure
On a Linux VPS, systemd can supervise the whole process from the outside:
[Service]
ExecStart=/usr/bin/python3 bot.py
Restart=on-failure
RestartSec=5
Enter fullscreen mode Exit fullscreen mode
This is solid for a VPS deployment, but it requires system-level access most PaaS platforms simply don't grant you — you can't install a systemd unit on Render or Railway.
Option 4: StayPresent's Subprocess Supervision
StayPresent restarts your script as a properly managed subprocess, with a restart ceiling, configurable backoff, and a counter that resets after sustained uptime — and it works identically whether you're on a PaaS platform, Docker, or a VPS:
import staypresent
staypresent.run(
"bot.py",
restart_on_crash=True,
max_restarts=5,
restart_delay=2.0,
restart_reset_after=60.0,
)
Enter fullscreen mode Exit fullscreen mode
Unlike the bash loop, this distinguishes a clean exit (sys.exit(0), never restarted) from a real crash (non-zero exit, restarted), and unlike the bare try/except approach, each restart is a genuinely fresh process — no leftover in-memory state from whatever caused the crash.
Comparing the Options
| Approach | Restart limit | Works on PaaS | Fresh process each restart | Distinguishes clean exit |
|---|---|---|---|---|
Bash while loop |
No | Yes | Yes | No |
try/except in main()
|
No | Yes | No | N/A |
| systemd | Yes | No (VPS only) | Yes | Yes |
| StayPresent | Yes | Yes | Yes | Yes |
Avoiding Crash Loops
Whatever approach you choose, an unlimited restart loop is dangerous — if the crash is caused by something that will fail identically every time (a missing environment variable, a bad database URL), restarting immediately and forever just wastes resources without ever succeeding. StayPresent's max_restarts caps consecutive failures, while restart_reset_after resets that counter once the script has proven it can stay up for a reasonable stretch — so a script that crashes once a week doesn't slowly creep toward its restart ceiling over unrelated, infrequent failures.
Full Example with StayPresent
import os
import staypresent
staypresent.web.json({"status": "running"})
staypresent.run(
"bot.py",
port=int(os.getenv("PORT", 8080)),
restart_on_crash=True,
max_restarts=5,
restart_delay=3.0,
restart_reset_after=90.0,
)
Enter fullscreen mode Exit fullscreen mode
If max_restarts is exhausted, staypresent.run() exits the whole process with the script's own exit code — which also means an outer layer like systemd or a PaaS's own restart policy can still catch it as a final backstop, if you want two layers of protection.
FAQs
Which option should I use for a bot deployed on Render or Railway?
StayPresent — systemd isn't available on managed PaaS platforms, and it also solves the separate HTTP-port requirement those platforms impose, which a bash loop or try/except doesn't address at all.
Can I combine a bash loop with StayPresent?
There's no real need to — StayPresent's restart logic already covers what a bash loop provides, with a proper ceiling and backoff on top.
Does restarting the process lose in-memory state?
Yes, by design — a fresh subprocess starts clean rather than continuing with whatever state existed when it crashed, which is usually the safer default unless your script explicitly persists state to disk or an external store.
Conclusion
There are several valid ways to auto restart a python script on crash, but they're not equivalent — a bash loop has no ceiling, a bare try/except doesn't get a fresh process, and systemd doesn't work on most PaaS platforms. StayPresent covers the gap those approaches leave: a genuine restart limit, fresh subprocesses, and compatibility with the managed hosting platforms most bots actually run on.
pip install staypresent[prod]
Enter fullscreen mode Exit fullscreen mode
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.