The best way to write looping code that runs forever?


#1

Hey folks,

So over the last couple of years I’ve built a couple of devices that run “eternally” using python and a while True loop. Think of things like lights that change colour depending on a third party API (like cheerlights) or nightlights for my kids that change colour depending on the time of day.

With all of these scripts I’ve noticed that at some point, eventually they will lock up. Not sure if it’s due to lack of memory (often using a Pi Zero) or some error in the code (I’ve found for example that sometimes the Cheerlights API will die for a bit and I haven’t figured out how to handle API failures well in Python yet, mostly because I’m a dirty dirty hacker).

Anyways… I was thinking, would a script that runs once and exits cleanly being fired at intervals by cron be more reliable over a longer period of time than something the while True approach above? Are there any downsides to this approach?

Thanks!

Andy

(I’m primarily interested because I’ve just ordered a Phat Stack and some pHats for an upcoming project that will operate multiple pHats and I was thinking it may be easier to just fire multiple scripts via Cron than having to jam it all into a single script that has the potential to fail in many different types of ways).


#2

You should, ideally, use systemd units to manage and auto-restart your script in case of failure. That said, by “locks up” do you mean the script hangs and ceases to produce output, or does it crash with an exception?

The cron-firing-at-intervals approach should be more reliable, but the key drawback is that you have no consistent state in your script so you have to take that into account when designing it.

Ultimately the script shouldn’t lock up- and in doing so suggests there might be a bug in one of the libraries you’re using that might be worth isolating and fixing.


#3

So an example I have is my nightlight, It’s a Zero W with a Unicorn pHat and a simple script set to change colour depending on the time of day.

Mostly it works, but after some time the device just stops changing colour. Most of the time I can no longer SSH in, so pulling the power and a quick reboot later its up and running again. There’s only imports are the unicorn hat and schedule).

But yet… sometimes it dies. I thought perhaps it was overheating, or somehow running out of memory.

If it’s the former, then I probably need to ventilate it (a few holes in the top should allow heat to escape effectively), but if it’s the latter I thought the cron method will ensure that the script never runs for so long that it can consume all the memory and kill the Pi.

This is the script (tweaked from the one Tanya wrote for the Zero W light kit) in case there is anything excessively stupid here:

#!/usr/bin/env python

from time import localtime, sleep
import unicornhat as u
import schedule

max_b = 0.5

# set_clear_on_exit()
u.clear()
u.brightness(max_b)

print("running...")
sleep(1)

def illuminate (r, g, b):
    u.set_all(r,g,b)    
    u.show()

schedule.every().day.at("06:00").do(illuminate, 255, 128, 0)
schedule.every().day.at("06:15").do(illuminate, 255, 255, 0)
schedule.every().day.at("06:30").do(illuminate, 0, 255, 0)
schedule.every().day.at("18:45").do(illuminate, 255, 0, 0)
schedule.every().day.at("21:40").do(illuminate, 255, 0, 0)

while True:
    schedule.run_pending()
    sleep(5)

This is just one example though… I’ve had a couple of other projects behave in the same way (although this is the most simple example that doesn’t rely on other API’s).


#4

There was actually a freezing bug in the underlying library for Unicorn HAT, mentioned here- https://github.com/jgarff/rpi_ws281x/issues/196

And fixed here: https://github.com/jgarff/rpi_ws281x/pull/197

It’s possible your library is out of date, or that another such bug has crept in.

Also, dang it, schedule was the library I was looking for earlier this week! :D


#5

Ha ha - I learnt about schedule from Tanya!

Thanks for the info on the bug - that could well be the cause of my troubles!


#6

I’ve updated and will pop back and post some more if it happens to freeze again in the future.

Thanks!


#7

It’s been running strong for 6 days now… looking good!