@classmethod
def dequeue(cls, exclude_ids=[]):
    """
        Claims the first available task and returns it. If there are no
        tasks available, returns None.

        For at-most-once delivery, commit the transaction before
        processing the task. For at-least-once delivery, dequeue and
        finish processing the task in the same transaction.

        To put a job back in the queue, you can just call
        .save(force_insert=True) on the returned object.
        """
    tasks = list(cls.objects.raw(
        """
            DELETE FROM dpq_job
            WHERE id = (
                SELECT id
                FROM dpq_job
                WHERE execute_at <= now()
                  AND NOT id = ANY(%s)
                ORDER BY priority DESC, created_at
                FOR UPDATE SKIP LOCKED
                LIMIT 1
            )
            RETURNING *;
            """
        , [list(exclude_ids)]))
    assert len(tasks) <= 1
    if tasks:
        return tasks[0]
    else:
        return None
