I want to make a function that executes at specified time interval, lets say at every 30 seconds, when the time is something like this: 12:37:00.000000
, 12:37:30.000000
, 12:38:00.000000
Now the easy approach would be to create a thread running a function that has a while loop that has a sleep(30)
at the end, thus waiting 30 seconds at the end. My application will be running 24/7, and in time, lets say maybe 2-3 hours from the start, the real time at which it will be executing that function would be X:X:00.5
or X:X:33.5
(because there is a lot of code above that sleep(30)
), thus delaying my work by a small margin every 30 seconds, and in few hours, by a pretty big margin.
What I'm searching for is a elegant method to set like an alarm that triggers at every 30 seconds, but always exactly 30 seconds, no more, no less, since precision is a must.
You could roll your own method:
from datetime import datetime, timedelta
import time
def every_30s():
print("fired at", datetime.now())
now = datetime.now()
# Align to the next 30 second event from the current time
if now.second >= 30:
next_fire = now.replace(second=30, microsecond=0) + timedelta(seconds=30)
else:
next_fire = now.replace(second=0, microsecond=0) + timedelta(seconds=30)
sleep = (next_fire - now).seconds - 1
while True:
# Sleep for most of the time
time.sleep(sleep)
# Wait until the precise time is reached
while datetime.now() < next_fire:
pass
every_30s()
next_fire += timedelta(seconds=30) # Advance 30 seconds
sleep = 29
This first aligns to the next 30 second interval and fires the event. It then sleep for 29 seconds (to reduce load) and then quickly checks if the next fire time has passed. The next fire time is then advanced 30 seconds.
This will ensure that the time never drifts. If there was heavy loading on the machine, it might fire slightly later, but the next event would be on time again.
Sample output:
fired at 2017-11-27 11:41:00
fired at 2017-11-27 11:41:30
fired at 2017-11-27 11:42:00
fired at 2017-11-27 11:42:30
fired at 2017-11-27 11:43:00
fired at 2017-11-27 11:43:30
fired at 2017-11-27 11:44:00