2

I've spent some significant time searching for something like this, but I think I'm not using the right search terms. Anyway, I have tasks that I want to do at certain times of the day, and these tasks are executable via a python-api.

Is there a module/method I can use to make sure these tasks run at the correct times, and ensures no tasks are skipped? If I wrote something myself it would look really ugly like:

import sys
import time

taskA = False
taskB = False
taskC = False

while True:
    now = time.strftime("%H:%M:%S")

    if taskA == False and now >= "10:00:00":
        <do TaskA>
        taskA = True
    if taskB == False and now >= "12:00:00":
        <do TaskB>
        taskB = True
    if taskC == False and now >= "16:20:07":
        <do TaskC>
        taskC = True
        sys.exit(0)

    time.sleep(1)

This is something that is currently on cron but I want to replace it with a python script.

Tom Jones
  • 111
  • 5
  • which platform you are running it on? A windows or linux? Is it serverless? Is it hosted on AWS or other cloud platform? – Anthony Kong Apr 05 '20 at 05:10
  • subprocess is a great module for executing scripts, i.e., `subprocess.call('python foo.py --bar=True')` – Bryce Wayne Apr 05 '20 at 05:12
  • If you really want to do it all in python, there are a number of different ways it could be accomplished. Yours honestly doesn't look too bad, as most of the time it will be sleeping. I implemented a quick and dirty task queue in an [answer](https://stackoverflow.com/a/60468741/3220135) to a different question that may get you going down the right path. – Aaron Apr 05 '20 at 05:12
  • also.. it sounds like you're on linux, so I'm gonna throw out [systemd timers](https://wiki.archlinux.org/index.php/Systemd/Timers) as a better alternative to cron. This is very resource light, and can do some very powerful things, like setting wake timers to run a process even if the system is in suspend. – Aaron Apr 05 '20 at 05:16
  • Correct I'm on linux. I need this in Python as I don't have access to edit cron – Tom Jones Apr 05 '20 at 05:18
  • Instead of the `while True` loop you could calculate the differential to figure out which process is cued next then sleep for a fixed amount of time. That is more efficient. – Bryce Wayne Apr 05 '20 at 05:22
  • 2
    Perhaps if you could explain why either cron or what you have here is insufficient, we could help better. Is it accuracy? reliability? resource usage? etc? – Aaron Apr 05 '20 at 05:23
  • I don't have access to edit cron. What I have here is insufficient because if I run the script at say 13:00:00, it will run TaskA and TaskB immediately, when I only want it to run TaskC at the correct time, though I guess I can take the time I start the script and don't run the task if the start time is after the scheduled time. Moreover, I will have 20+ times, and having a flag for each for whether it's run or not seems terribly inefficient. Finally, it would be surprising if there wasn't a much much better way to do this... – Tom Jones Apr 05 '20 at 05:32
  • What about a *user* crontab(1)? – Roland Smith Apr 05 '20 at 06:09
  • Heard something about a Python scheduler on a podcast. https://www.listennotes.com/podcasts/the-python/the-advanced-python-task-tKCrakWHhZb/ here's the github for it. https://github.com/agronholm/apscheduler all-Python, time-based and I really kinda remember it being talked up as a cron alternative (rather than a Celery equivalent). 2.5k stars and been around at least 4 yrs, so might help. – JL Peyret Apr 05 '20 at 06:19

2 Answers2

1

IIUC: Here is one simple solution, You can use threading.Timer function from the threading package which starts a thread that executes a function after a specified interval has passed. You can use this:

from threading import Timer
from datetime import datetime, date
from time import sleep

def task_a():
    sleep(5) #--> perform some work
    print("Task A, completed at:", datetime.today().time())

def task_b():
    sleep(10) #--> perform some work
    print("Task B, completed at", datetime.today().time())

def task_c():
   sleep(20) #--> perform some work
   print("Task C, completed at", datetime.today().time())

now = datetime.today().time()

taska_start = datetime.strptime("10:00:00", "%H:%M:%S").time()
taskb_start = datetime.strptime("12:00:00", "%H:%M:%S").time()
taskc_start = datetime.strptime("16:20:07", "%H:%M:%S").time()

tasks = [(taska_start, task_a), (taskb_start, task_b), (taskc_start, task_c)]

for task_start, task in tasks:
    if datetime.combine(date.min, task_start) > datetime.combine(date.min, now):
        diff = datetime.combine(date.min, task_start) > datetime.combine(date.min, now)
        t = Timer(diff.seconds, task)
        t.start()

For Example,

If current time 12:00:00 and suppose task_a is scheduled to run at 13:00:00, task_b is scheduled to run at 13:30:00 and task_c is scheduled to run at 14:00:00.. Then after executing the script task_a will run after 60 seconds, task_b will run after 90, and task_c will run after 120 seconds from the current time.

Sample Result:

Task A, completed at: 13:00:05
Task B, completed at: 13:30:10
Task C, completed at: 14:00:20
Shubham Sharma
  • 68,127
  • 6
  • 24
  • 53
0

You can use a CRON Job. Python Crontab allows you to do such a thing. You can check how to use it here: https://stackabuse.com/scheduling-jobs-with-python-crontab/

michmich112
  • 744
  • 4
  • 8