0

I have a bot that has to run continuously but I want it to call one particular functionality only during working time of business day. Someone suggested me to do that with crontab but If I am not mistaken, this is not possible for two reasons:

  1. I need to run my bot as a docker image (so in ALpine-Lynux) and crontab does not support lynux os

  2. it just allows me to repeat an action every given seconds/minutes/hours/days and there is no possible way to "say it" ("if I am in a working time of a business day run the action continuously otherwise just wait 9am of next working day")

This is what I am building, I would like to know which of the 2 "versions" of the wait function is better but if you know any smartest way, it will be appreciated a lot

def waiting_or_not():
    current_date = datetime.now(timezone('Europe/Rome'))
    need_to_wait = True
    if not isbday(current_date, holidays=Italy()) or current_date.hour > 18:
        next_run = get_next_working_day(current_date.replace(hour=9, minute=0, second=0) + timedelta(days=1))
    elif current_date.hour < 9:
        next_run = current_date.replace(hour=9, minute=0, second=0)
    else:
        need_to_wait = False
    if need_to_wait:
        seconds_to_wait = (next_run - current_date).total_seconds()
        # insert log
        wait(next_run)


def get_next_working_day(date_):
    while not isbday(date_):
        date_ += timedelta(days=1)
    return date_


def wait(next_run):
    '''
     I don't like this version at all. It seems to me ridiculous to "ask" continuously 
     the time. If it is friday evening after 18 and I need to wait until Monday morning,
     there will be billions of useless checks.
    '''
    current_date = datetime.now(timezone('Europe/Rome'))
    while current_date < next_run:
        current_date = datetime.now(timezone('Europe/Rome'))

def wait(next_run):
    '''
     I read sleep function is not precise and has big problems with huge numbers of seconds
    '''
    current_date = datetime.now(timezone('Europe/Rome'))
    time.sleep((next_run - current_date).total_seconds())

1 Answers1

0
  • As you already said, Option One will continuously loop. This will keep one core of your CPU occupied at nearly 100%, wasting a lot of computing resources and energy.

  • Option Two is better, and in fact a common way to achieve this. According to this question, the limit for sleep is about somewhere around 4 million seconds, which is around 46 days. If you are actually worried about that, you can use something like this version:

SLEEP_LIMIT = 1000000
def wait(next_run):
    while True:
        seconds_till_next_run = (
           next_run -
           datetime.now(timezone('Europe/Rome'))).total_seconds()
        )
        if seconds_till_next_run > SLEEP_LIMIT:
            time.sleep(SLEEP_LIMIT)
        elif seconds_till_next_run > 0:
            time.sleep(seconds_till_next_run)
        else:
            break
  • Regarding the precision of time.sleep: it might not be accurate down to the millisecond, but that should be acceptable for any task performed in a python script. The operating system might introduce additional delays (typically also in the millisecond range) due to scheduling of other tasks anyways.
ChrisB
  • 1,540
  • 6
  • 20
  • thank you for your prompt answer. Your solution is exactly what I was looking for (I do not know why it did not come to my mind something like that) –  Mar 31 '23 at 12:54