Django Q

repository·master·Indexed 23 days ago

https://github.com/koed00/django-q

A multiprocessing distributed task queue for Django (version 1.3.9) that supports asynchronous tasks, scheduled/cron jobs, and multiple brokers including Redis, SQS, MongoDB, and the Django ORM. It features a hierarchical process model consisting of a Cluster, Sentinel, Pusher, Workers, and Monitor to ensure reliability and worker reincarnation.

Tokens
23K
Snippets
42
Records
156
Agent score
83%

What's inside django-q

  1. Overview of Django Q features

    master

    Django Q is a native Django task queue, scheduler, and worker application that utilizes Python multiprocessing. It is designed to handle asynchronous tasks, scheduled/cron/repeated tasks, and provides robust monitoring and integration capabilities.

    Key features include:

    • Worker Pools: Uses multiprocessing worker pools.
    • Task Management: Supports asynchronous tasks, scheduled tasks, cron jobs, and repeated tasks.
    • Reliability: Supports signed and compressed packages, and tracks failures/successes in a database or cache.
    • Task Orchestration: Supports result hooks, groups, and chains.
    • Broker Support: Compatible with Redis, Disque, IronMQ, SQS, MongoDB, or the Django ORM.
    • Integrations: Django Admin integration, Rollbar and Sentry support, and PaaS compatibility for multiple instances.
    • Monitoring: Multi-cluster monitor support.
  2. Manage Django Q tasks via Django Admin

    master

    Django Q integrates with the standard Django admin interface using proxy models. When you access the Django Q admin pages, you will find three primary models for monitoring and managing tasks:

    1. Successful tasks: Displays tasks that executed without errors. You can view details, delete them, or filter by group (schedule name or group ID). The table is searchable by name, func, and group.
    2. Failed tasks: Displays tasks that encountered errors. The error details are typically stored in the result field. You can resubmit a failed task to the queue directly from the admin action menu.
    3. Scheduled tasks: Allows you to create, edit, delete, or monitor tasks set to run at specific intervals.

    Note: If you have configured save_limit to prevent saving successful tasks, you will only see failed results in the admin.

  3. Understand Django Q Brokers and Delivery Guarantees

    master

    A Broker sits between your Django instances and your Django Q cluster instances, accepting, saving, and delivering task packages.

    Delivery Guarantees and Receipts

    Django Q supports brokers with message receipts (e.g., Disque, IronMQ, Amazon SQS, MongoDB, Django ORM). These brokers guarantee delivery by waiting for the cluster to send a receipt after a task is processed. If no receipt is received within a set time, the task is put back in the queue.

    Important considerations for brokers with receipts:

    • Retry Timer: Use the retry setting to control how long the broker waits for completion.
    • Timing: Do not set the retry timer to a value lower than or equal to the task timeout. The retry time includes the time the task spends waiting in the cluster's internal queue.
    • Queue Limit: Avoid setting queue_limit so high that tasks time out while waiting to be processed.
    • Duplicate Execution: If a task is worked on twice, the result is updated with the latest results. However, if a previous run already succeeded, the new result will be discarded.

    Note on Redis: The default Redis broker does not support message receipts. In the event of a catastrophic cluster failure or worker timeout, tasks being executed may be lost.

  4. Run multiple clusters across machines

    master

    You can run multiple clusters on different machines to work on the same queue. For this to work correctly, you must ensure the following requirements are met:

    1. They must connect to the same broker.
    2. They must use the same cluster name (configured in settings).
    3. They must share the same Django SECRET_KEY.
  5. How Django Q architecture works

    master

    Django Q uses a distributed architecture consisting of several specialized processes to manage task execution and reliability:

    • Signed Tasks: Tasks are pickled and signed using Django's django.core.signing module with the SECRET_KEY and cluster name as salt. This ensures only authorized clusters can execute tasks. Tasks can optionally be compressed.
    • Broker: Collects task packages from Django instances and queues them. It provides at-least-once delivery by keeping tasks until acknowledged (if supported) or re-queueing them after a timeout.
    • Pusher: Continuously monitors the broker for new tasks, verifies signatures, unpacks them, and moves them into the internal Task Queue.
    • Worker: Pulls tasks from the Task Queue, executes them, and saves results (or errors) to the package. It uses a countdown timer with the Sentinel to signal active work.
    • Monitor: Watches the Result Queue for processed packages and saves results/failures to the Django database or cache backend.
    • Sentinel: The supervisor process. It spawns all other processes and monitors their health. If a worker or process crashes or times out, the Sentinel reincarnates it.
    • Scheduler: Runs twice a minute to check for scheduled tasks, creating tasks from schedules and managing repeat counts.
    • Stop Procedure: A graceful shutdown sequence where the Sentinel stops the Pusher, injects 'poison pills' into the Task and Result queues to clear them, and waits for all processes to exit.
  6. Manage groups of tasks with result_group and async_iter

    master

    Django Q provides mechanisms to handle multiple related tasks as a single unit.

    Using Task Groups

    1. Assign a group name to multiple async_task calls.
    2. Use result_group(group_name, count=N) to wait for and retrieve the results once a specific number of tasks in that group have completed.
    3. Use delete_group(group_name) to clear previous results from the cache.

    Using async_iter

    async_iter is a high-level abstraction that automatically utilizes the cache backend and groups to return a single result from an iterable of arguments. It is often cleaner than manually managing groups for batch processing.

  7. Monitor Queued tasks (ORM Broker only)

    master

    If you are using the orm_broker broker, an additional admin view for Queued tasks is enabled. This view shows all task packages currently waiting in the broker queue.

    • Lock column: Indicates when the package was picked up by the cluster; this is used to determine if a task has expired.
    • Management: You can edit or delete queued tasks directly from this view, which is useful for development.
  8. How timeouts and worker reincarnation work

    master

    Django Q uses a watchdog mechanism to handle hung workers:

    1. Before executing a task, a Worker sets a countdown timer with the Sentinel.
    2. The timer is reset after the task execution completes.
    3. The Sentinel continuously checks these timers. If a timer reaches zero (indicating a worker is stuck or unresponsive), the Sentinel terminates that worker and reincarnates a new one.
  9. Configure Schedule repeats

    master

    The Schedule.repeats attribute controls how many times a scheduled task runs.

    • Finite runs: Set a positive integer (e.g., 24) to run the task a specific number of times. The count decrements each time the schedule runs.
    • Indefinite runs: Set repeats to -1. The schedule will run indefinitely, and the count will continue to decrement (e.g., -1, -2, -3...), serving as an execution counter.
    • Pausing: Set repeats to 0 to pause a schedule.
    • Schedule.ONCE type:
      • A positive number keeps the schedule but prevents it from running again.
      • A negative number causes the schedule to be deleted from the database.
      • To re-run a ONCE schedule that was paused (repeats set to 0), change the repeats to a non-zero value and set a new run time.
  10. Implement a custom error reporter plugin

    master

    To create a custom error reporting plugin for Django Q, you must provide a class that satisfies the following requirements:

    1. Constructor: The class must accept keyword arguments (**kwargs). These arguments are sourced directly from the Q_CLUSTER configuration in settings.py.
    2. report method: The class must implement a report method. This method is automatically called by the Django Q cluster whenever an error occurs.

    Example structure for a plugin class:

    class MyCustomReporter:
        def __init__(self, **kwargs):
            # Settings from Q_CLUSTER are available here
            self.api_key = kwargs.get('api_key')
    
        def report(self, exception, task, cluster):
            # Logic to send the exception to your service
            pass
  11. Understand cluster monitor metrics (Legend)

    master

    When using qmonitor, the following metrics are displayed:

    • State: The current lifecycle stage of the cluster:
      • Starting: Spawning workers and getting ready.
      • Idle: Ready, but no tasks to process.
      • Working: Actively processing tasks.
      • Stopping: Not taking new tasks; finishing current ones.
      • Stopped: Shutting down after all tasks are processed.
    • TQ (Task Queue): Number of tasks in the queue. If this rises continuously, your cluster cannot keep up. You can set a queue_limit in your cluster configuration to trigger a warning.
    • RQ (Result Queue): Number of results waiting to be saved. This may clear slower than the task queue because results are saved via a single process accessing the database.
    • RC (Reincarnations): Number of times processes were restarted due to recycle, sudden death, or timeout. High numbers suggest task errors or severe timeouts.
    • Up (Uptime): Time elapsed since the cluster started.
    • Pool: The current number of workers in the cluster.
  12. Handle task completion with hooks

    master

    You can pass a hook argument to async_task to specify a function that will be called automatically after the task completes. The hook function receives the task object as its argument, which contains the success status and the result of the original task.

    This is useful for workflows where a long-running task (like report generation) needs to trigger a follow-up action (like emailing the result) based on whether the task succeeded or failed.

    # views.py
    def create_report(request):
        async_task('tasks.create_html_report',
                request.user,
                hook='tasks.email_report')
    
    # tasks.py
    def email_report(task):
        if task.success:
            # Email the report using task.result
            async_task('django.core.mail.send_mail',
                    'The report you requested',
                    task.result,
                    'from@example.com',
                    task.args[0].email)
        else:
            # Handle failure
            async_task('django.core.mail.mail_admins',
                    'Report generation failed',
                    task.result)