Django - run a function every x seconds

后端 未结 3 1856
梦毁少年i
梦毁少年i 2020-12-23 12:00

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). Ho

3条回答
  •  悲哀的现实
    2020-12-23 12:48

    This answer expands on Oz123's answer a little bit.

    In order to get things working, I created a file called mainapp/jobs.py to contain my scheduled jobs. Then, in my apps.py module, I put from . import jobs in the ready method. Here's my entire apps.py file:

    from django.apps import AppConfig
    import os
    
    class MainappConfig(AppConfig):
        name = 'mainapp'
    
        def ready(self):
            from . import jobs
    
            if os.environ.get('RUN_MAIN', None) != 'true':
                jobs.start_scheduler()
    

    (The RUN_MAIN check is because python manage.py runserver runs the ready method twice—once in each of two processes—but we only want to run it once.)

    Now, here's what I put in my jobs.py file. First, the imports. You'll need to import Scheduler, threading and time as below. The F and UserHolding imports are just for what my job does; you won't import these.

    from django.db.models import F
    from schedule import Scheduler
    import threading
    import time
    
    from .models import UserHolding
    

    Next, write the function you want to schedule. The following is purely an example; your function won't look anything like this.

    def give_admin_gold():
        admin_gold_holding = (UserHolding.objects
            .filter(inventory__user__username='admin', commodity__name='gold'))
    
        admin_gold_holding.update(amount=F('amount') + 1)
    

    Next, monkey-patch the schedule module by adding a run_continuously method to its Scheduler class. Do this by using the below code, which is copied verbatim from Oz123's answer.

    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
    

    Finally, define a function to create a Scheduler object, wire up your job, and call the scheduler's run_continuously method.

    def start_scheduler():
        scheduler = Scheduler()
        scheduler.every().second.do(give_admin_gold)
        scheduler.run_continuously()
    

提交回复
热议问题