I'm working on a Django app. I have an API endpoint, which if requested, must carry out a function that must be repeated a few times (until a certain condition is true). How I'm dealing with it right now is -
def shut_down(request): # Do some stuff while True: result = some_fn() if result: break time.sleep(2) return True
While I know that this is a terrible approach and that I shouldn't be blocking for 2 seconds, I can't figure out how to get around it.
This works, after say a wait of 4 seconds. But I'd like something that keeps the loop running in the background, and stop once some_fn returns True. (Also, it is certain that some_fn will return True)
EDIT -
Reading Oz123's response gave me an idea which seems to work. Here's what I did -
def shut_down(params): # Do some stuff # Offload the blocking job to a new thread t = threading.Thread(target=some_fn, args=(id, ), kwargs={}) t.setDaemon(True) t.start() return True def some_fn(id): while True: # Do the job, get result in res # If the job is done, return. Or sleep the thread for 2 seconds before trying again. if res: return else: time.sleep(2)
This does the job for me. It's simple but I don't know how efficient multithreading is in conjunction with Django.
If anyone can point out pitfalls of this, criticism is appreciated.
With the help of the Schedule module, we can make a python script that will be executed in every given particular time interval. with this function schedule. every(5). minutes.do(func) function will call every 5 minutes.
start() and stop() are safe to call multiple times even if the timer has already started/stopped. function to be called can have positional and named arguments. You can change interval anytime, it will be effective after next run. Same for args , kwargs and even function !
Timer() to schedule function calls. However, if you want a particular function to wait for a specific time in Python, we can use the threading. Timer() method from the threading module. We'll show a simple example, which schedules a function call every 5 seconds.
For many small projects celery is overkill. For those projects you can use schedule, it's very easy to use.
With this library you can make any function execute a task periodically:
import schedule import time def job(): print("I'm working...") schedule.every(10).minutes.do(job) schedule.every().hour.do(job) schedule.every().day.at("10:30").do(job) schedule.every().monday.do(job) schedule.every().wednesday.at("13:15").do(job) while True: schedule.run_pending() time.sleep(1)
The example runs in a blocking manner, but if you look in the FAQ, you will find that you can also run tasks in a parallel thread, such that you are not blocking, and remove the task once not needed anymore:
import threading import time from schedule import Scheduler def run_continuously(self, interval=1): """Continuously run, while executing pending jobs at each elapsed time interval. @return cease_continuous_run: threading.Event which can be set to cease continuous run. Please note that it is *intended behavior that run_continuously() does not run missed jobs*. For example, if you've registered a job that should run every minute and you set a continuous run interval of one hour then your job won't be run 60 times at each interval but only once. """ cease_continuous_run = threading.Event() class ScheduleThread(threading.Thread): @classmethod def run(cls): while not cease_continuous_run.is_set(): self.run_pending() time.sleep(interval) continuous_thread = ScheduleThread() continuous_thread.setDaemon(True) continuous_thread.start() return cease_continuous_run Scheduler.run_continuously = run_continuously
Here is an example for usage in a class method:
def foo(self): ... if some_condition(): return schedule.CancelJob # a job can dequeue it # can be put in __enter__ or __init__ self._job_stop = self.scheduler.run_continuously() logger.debug("doing foo"...) self.foo() # call foo self.scheduler.every(5).seconds.do( self.foo) # schedule foo for running every 5 seconds ... # later on foo is not needed any more: self._job_stop.set() ... def __exit__(self, exec_type, exc_value, traceback): # if the jobs are not stop, you can stop them self._job_stop.set()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With