Set up a scheduled job?

后端 未结 24 2527
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-22 01:13

I\'ve been working on a web app using Django, and I\'m curious if there is a way to schedule a job to run periodically.

Basically I just want to run through the dat

相关标签:
24条回答
  • 2020-11-22 01:49

    Celery is a distributed task queue, built on AMQP (RabbitMQ). It also handles periodic tasks in a cron-like fashion (see periodic tasks). Depending on your app, it might be worth a gander.

    Celery is pretty easy to set up with django (docs), and periodic tasks will actually skip missed tasks in case of a downtime. Celery also has built-in retry mechanisms, in case a task fails.

    0 讨论(0)
  • 2020-11-22 01:50

    Brian Neal's suggestion of running management commands via cron works well, but if you're looking for something a little more robust (yet not as elaborate as Celery) I'd look into a library like Kronos:

    # app/cron.py
    
    import kronos
    
    @kronos.register('0 * * * *')
    def task():
        pass
    
    0 讨论(0)
  • 2020-11-22 01:51

    You should definitely check out django-q! It requires no additional configuration and has quite possibly everything needed to handle any production issues on commercial projects.

    It's actively developed and integrates very well with django, django ORM, mongo, redis. Here is my configuration:

    # django-q
    # -------------------------------------------------------------------------
    # See: http://django-q.readthedocs.io/en/latest/configure.html
    Q_CLUSTER = {
        # Match recommended settings from docs.
        'name': 'DjangoORM',
        'workers': 4,
        'queue_limit': 50,
        'bulk': 10,
        'orm': 'default',
    
    # Custom Settings
    # ---------------
    # Limit the amount of successful tasks saved to Django.
    'save_limit': 10000,
    
    # See https://github.com/Koed00/django-q/issues/110.
    'catch_up': False,
    
    # Number of seconds a worker can spend on a task before it's terminated.
    'timeout': 60 * 5,
    
    # Number of seconds a broker will wait for a cluster to finish a task before presenting it again. This needs to be
    # longer than `timeout`, otherwise the same task will be processed multiple times.
    'retry': 60 * 6,
    
    # Whether to force all async() calls to be run with sync=True (making them synchronous).
    'sync': False,
    
    # Redirect worker exceptions directly to Sentry error reporter.
    'error_reporter': {
        'sentry': RAVEN_CONFIG,
    },
    }
    
    0 讨论(0)
  • 2020-11-22 01:53

    For simple dockerized projects, I could not really see any existing answer fit.

    So I wrote a very barebones solution without the need of external libraries or triggers, which runs on its own. No external os-cron needed, should work in every environment.

    It works by adding a middleware: middleware.py

    import threading
    
    def should_run(name, seconds_interval):
        from application.models import CronJob
        from django.utils.timezone import now
    
        try:
            c = CronJob.objects.get(name=name)
        except CronJob.DoesNotExist:
            CronJob(name=name, last_ran=now()).save()
            return True
    
        if (now() - c.last_ran).total_seconds() >= seconds_interval:
            c.last_ran = now()
            c.save()
            return True
    
        return False
    
    
    class CronTask:
        def __init__(self, name, seconds_interval, function):
            self.name = name
            self.seconds_interval = seconds_interval
            self.function = function
    
    
    def cron_worker(*_):
        if not should_run("main", 60):
            return
    
        # customize this part:
        from application.models import Event
        tasks = [
            CronTask("events", 60 * 30, Event.clean_stale_objects),
            # ...
        ]
    
        for task in tasks:
            if should_run(task.name, task.seconds_interval):
                task.function()
    
    
    def cron_middleware(get_response):
    
        def middleware(request):
            response = get_response(request)
            threading.Thread(target=cron_worker).start()
            return response
    
        return middleware
    

    models/cron.py:

    from django.db import models
    
    
    class CronJob(models.Model):
        name = models.CharField(max_length=10, primary_key=True)
        last_ran = models.DateTimeField()
    

    settings.py:

    MIDDLEWARE = [
        ...
        'application.middleware.cron_middleware',
        ...
    ]
    
    0 讨论(0)
  • 2020-11-22 01:54

    A more modern solution (compared to Celery) is Django Q: https://django-q.readthedocs.io/en/latest/index.html

    It has great documentation and is easy to grok. Windows support is lacking, because Windows does not support process forking. But it works fine if you create your dev environment using the Windows for Linux Subsystem.

    0 讨论(0)
  • 2020-11-22 01:55

    I personally use cron, but the Jobs Scheduling parts of django-extensions looks interesting.

    0 讨论(0)
提交回复
热议问题