DEV Community

John Wick
John Wick

Posted on

Run Python Bots Without Sleep On Render With StayPresent

Deploy Python Bots on Render Without Sleep Using StayPresent

Render is one of the most popular free hosting platforms for small Python projects, but it comes with a well-known catch: free-tier web services spin down after a period of inactivity and require a fresh incoming request to wake back up. For a render python bot — a Discord bot, Telegram bot, or scraper — that "wake up" delay can mean minutes of downtime every time the service goes idle.

This guide covers exactly how Render's sleep behavior works, and how to eliminate it using StayPresent.

Table of Contents

  1. Understanding Render's Free Tier
  2. Why HTTP Port Requirements Matter
  3. Setting Up StayPresent for Render
  4. Health Checks Explained
  5. Self-Ping to Avoid Idle Sleep
  6. Crash Recovery on Render
  7. Full Working Example
  8. Best Practices
  9. Common Mistakes
  10. FAQs
  11. Conclusion

Understanding Render's Free Tier

Render's free web services sleep after roughly 15 minutes without incoming HTTP traffic. Once asleep, the next request has to spin the container back up before it responds, so real users (or a bot's own polling loop) experience a delay. Render also expects your web service to bind to a port it provides via the PORT environment variable — if nothing is listening there, Render's own health checks will consider the deploy unhealthy.

[Render Health Check] --HTTP GET--> [Your Service on $PORT]
                                        |
                                No response = unhealthy
Enter fullscreen mode Exit fullscreen mode

Why HTTP Port Requirements Matter

A typical Telegram or Discord bot doesn't open an HTTP port — it just connects outward to Telegram's or Discord's API and waits for events. That's perfectly normal bot behavior, but it fails Render's expectations for a web service. The fix isn't to change how your bot works; it's to run a small HTTP server next to it, purely so Render has something to check.

Setting Up StayPresent for Render

Install the production extra so Waitress serves the app instead of Flask's development server:

pip install staypresent[prod]
Enter fullscreen mode Exit fullscreen mode

Then in your entry point (commonly main.py):

import os
import staypresent

staypresent.web.json({
    "status": "running",
    "service": "my-telegram-bot"
})

staypresent.run(
    "bot.py",
    port=int(os.getenv("PORT", 8080))
)
Enter fullscreen mode Exit fullscreen mode

Render's start command should simply run this file:

python main.py
Enter fullscreen mode Exit fullscreen mode

Health Checks Explained

StayPresent automatically exposes /health, which always returns {"status": "ok"}. In Render's dashboard, you can point the service's health check path at /health instead of /, keeping your root route free to serve a status page, a JSON payload, or nothing more than the default {"message": "I'm Present"}.

Self-Ping to Avoid Idle Sleep

Render's sleep timer only cares about incoming traffic. If nothing external is hitting your service, staypresent.cron() can generate that traffic itself by pinging your own public URL on a schedule:

import os
import staypresent

staypresent.cron(
    "https://my-app.onrender.com",
    interval=240,  # every 4 minutes
)

staypresent.run(
    "bot.py",
    port=int(os.getenv("PORT", 8080))
)
Enter fullscreen mode Exit fullscreen mode

This has to target your public URL — pinging 0.0.0.0 or 127.0.0.1 never leaves the machine, so it won't count as activity from Render's perspective.

You can also react to failures with a callback:

staypresent.cron(
    "https://my-app.onrender.com",
    interval=240,
    on_failure=lambda r: print(f"warm ping failed: {r['error']}"),
)
Enter fullscreen mode Exit fullscreen mode

Crash Recovery on Render

Bots crash — a bad API response, a network blip, an unhandled exception. By default, StayPresent restarts your bot process automatically on a non-zero exit code:

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

max_restarts only counts consecutive crashes — if the bot stays up longer than restart_reset_after (60 seconds by default), the counter resets to zero. If restarts are exhausted, StayPresent exits the whole process with the bot's original exit code, so Render's own platform-level restart policy can take over as a last resort.

Full Working Example

import os
import staypresent

staypresent.web.json({"status": "running"})

staypresent.cron("https://my-app.onrender.com", interval=240)

staypresent.run(
    "bot.py",
    port=int(os.getenv("PORT", 8080)),
    threads=8,
    restart_on_crash=True,
    max_restarts=5,
)
Enter fullscreen mode Exit fullscreen mode

Best Practices

  • Point Render's health check at /health, not /, if your root route serves anything custom.
  • Set interval on cron() comfortably below Render's ~15-minute idle window — 4–5 minutes is a safe default.
  • Use the prod extra in any real deployment so Waitress handles concurrency instead of Flask's dev server.

Common Mistakes

  • Pinging the local bind address instead of the public Render URL. staypresent.cron("0.0.0.0", port=8080) only tests that your own server responds locally; it does nothing to prevent Render's sleep timer.
  • Forgetting to read $PORT from the environment. Render assigns this dynamically — hardcoding port=8080 will work locally but may not match what Render expects.
  • Assuming self-ping bypasses Render's hard limits. It only prevents inactivity sleep; it can't work around account-level suspensions or free-tier quotas.

FAQs

Does self-ping guarantee 24/7 uptime?
It prevents inactivity-based sleep, but final availability still depends on Render's own policies and limits.

Can I use the same setup on Railway?
Yes — Railway also injects $PORT automatically, so the exact same main.py works unchanged.

Do I need Waitress?
No, it's optional, but recommended for production traffic. Without it, StayPresent falls back to Flask's built-in server.

Conclusion

A render python bot doesn't have to sleep. Pair Render's $PORT requirement, StayPresent's built-in /health endpoint, an optional self-ping via cron(), and automatic crash recovery, and you get a bot that stays online, restarts itself when something goes wrong, and requires almost no boilerplate to set up.

pip install staypresent[prod]
Enter fullscreen mode Exit fullscreen mode

Top comments (0)