5

I've seen that I can repeat a function with python every x seconds by using a event loop library in this post:

import sched, time
s = sched.scheduler(time.time, time.sleep)
def do_something(sc): 
    print("Doing stuff...")
    # do your stuff
    s.enter(60, 1, do_something, (sc,))

s.enter(60, 1, do_something, (s,))
s.run()

But I need something slightly different: I need that the function will be called at every system clock minute: at 11:44:00PM, 11:45:00PM and so on.

How can I achieve this result?

Jepessen
  • 11,744
  • 14
  • 82
  • 149
  • 1
    similar to https://stackoverflow.com/questions/70580585/python-does-something-every-5-minutes/70581073 – Wups Jan 21 '22 at 10:26
  • A quick search on PyPI gives at least 2 projects for a Python scheduler: croniter and schedule. Both look maintained and documented even if the first only advertise a beta quality level. You could have a look at them... – Serge Ballesta Jan 21 '22 at 10:30

3 Answers3

7

Use schedule.

import schedule
import time

schedule.every().minute.at(':00').do(do_something, sc)
while True:
    schedule.run_pending()
    time.sleep(.1)

If do_something takes more than a minute, threadidize it before passing it to do.

import threading
def do_something_threaded(sc):
    threading.Thread(target=do_something, args=(sc,)).start()
timgeb
  • 76,762
  • 20
  • 123
  • 145
1

If you think along the lines of a forever running program, you have to ping the system time using something like now = datetime.now(). Now if you want 1 sec accuracy to catch that :00 window, that means you have to ping a lot more often.

Usually a better way is to schedule the script execution outside using Windows Task Scheduler or Crontab in Linux systems.

For example, this should run every XX:YY:00:

* * * * * python run_script.py
Register Sole
  • 3,206
  • 1
  • 14
  • 22
  • Unfortunately I cannot run the script every minute from a scheduler, but it should happen inside the script. It's a script that retrieve data from a websocket and at every system clock minute it should rearrange data for storing them in a database. – Jepessen Jan 21 '22 at 10:23
  • I see, sounds like you are doing complex event processing. Have you considered frameworks for streaming data processing like Apache Beam? They should have some windowing function for this purpose. – Register Sole Jan 21 '22 at 10:28
  • It seems an overkill, I need only to take numeric data from the websocket message and every minute check the maximum and minimum value. But since they will be historical data they must calculated at every system clock minute, not every generic 60 seconds. – Jepessen Jan 21 '22 at 10:33
  • Ok in that case, you need some messaging mechanism to aggregate multiple socket messages no? For example, use the socket client to send the messages into a queue. Then you can use the crontab to invoke a script that polls the queue every `:00` and aggregate whatever is there. Will this work? `listener -> queue -> (cron to poll every 00) aggregate_script`. – Register Sole Jan 21 '22 at 10:40
1

Exactly 0 is very hard to accomplish (since there is always a small delay) but You can check if the minute has changed:

import datetime
minute = None
while True:
    if datetime.datetime.now().minute != minute:
        print(f'Do something {datetime.datetime.now()}')
        minute = datetime.datetime.now().minute 

result at my mahcine:

Do something 2022-01-21 11:24:39.393919
Do something 2022-01-21 11:25:00.000208

So it checks if there is a new minute and calls again the datetime function. The delay is around 0.2 milliseconds.

3dSpatialUser
  • 2,034
  • 1
  • 9
  • 18