В чем различия между декораторами `@task` и `@shared_task` в Celery?

Ответ

В Celery @task и @shared_task — это декораторы, используемые для определения асинхронных задач. Основное различие между ними заключается в способе их привязки к экземпляру приложения Celery.

  1. @task (Привязка к экземпляру приложения Celery)

    • Назначение: Используется для определения задач, которые явно привязаны к конкретному экземпляру приложения Celery.
    • Использование: Декоратор @task вызывается через объект приложения Celery (например, app.task). Это означает, что задача становится частью этого конкретного приложения.
    • Контекст: Если у вас несколько приложений Celery или вы работаете в среде, где приложение Celery может быть не инициализировано при импорте модуля (например, в некоторых тестах или скриптах), использование @task может потребовать дополнительной настройки или привести к ошибкам.

    Пример app.task:

    from celery import Celery
    
    app = Celery('my_app', broker='redis://localhost:6379/0')
    
    @app.task
    def add_bound(x, y):
        return x + y
  2. @shared_task (Независимая от приложения задача)

    • Назначение: Используется для определения задач, которые не привязаны к конкретному экземпляру приложения Celery. Они могут быть импортированы и использованы любым приложением Celery, которое их обнаружит.
    • Использование: Декоратор @shared_task импортируется напрямую из модуля celery (например, from celery import shared_task).
    • Контекст: Это предпочтительный способ определения задач в большинстве проектов, особенно в Django, где задачи могут быть определены в разных приложениях и должны быть доступны глобально без явной привязки к одному экземпляру Celery app.

    Пример shared_task:

    from celery import shared_task
    
    @shared_task
    def add_shared(x, y):
        return x + y

Когда использовать:

  • @shared_task: Рекомендуется для большинства случаев, особенно в проектах на Django или при создании библиотек. Это обеспечивает гибкость и позволяет легко импортировать задачи из любого места без необходимости передавать экземпляр app.
  • @task: Используется, когда вам нужна специфическая привязка задачи к определенному экземпляру приложения Celery, например, если у вас есть несколько Celery приложений с разными конфигурациями, и задача должна принадлежать только одному из них. Однако, в большинстве случаев, @shared_task является более универсальным и простым в использовании.

Ответ 18+ 🔞

О, слушай, смотри, тут про Celery, про эти ёбаные декораторы @task и @shared_task. Вроде одно и то же, а нихуя — разница есть, как между "пойти нахуй" и "пойти нахуй, но с чувством, с толком, с расстановкой".

Вот смотри, блядь, чтобы не обосраться с конфигурацией.

@task — это как привязанный раб к конкретной конторе. Этот декоратор ты цепляешь прямо к своему экземпляру приложения Celery. Типа app.task. Задача становится его личной собственностью, его сучкой. Если у тебя вдруг несколько этих Celery-приложений бегает, или ты импортируешь модуль, а приложение ещё не инициализировано — тут тебе и пиздец, Колян. Всё посыпется, как карточный домик от чиха.

from celery import Celery

app = Celery('my_app', broker='redis://localhost:6379/0')

@app.task  # Вот, привязал намертво к этой конкретной 'app'. Как собака на цепи.
def add_bound(x, y):
    return x + y

Вот, видишь? add_bound теперь принадлежит этому app. Другой дяде такой задачи не даст, жадный уёбок.

А вот @shared_task — это свободная касса, блядь. Независимый художник. Его импортируешь прямо из celery и вешаешь на любую функцию. Эта штука не привязана ни к какому конкретному приложению. Она как бродячий пёс — любой Celery-инстанс, который её увидит, может взять и выполнить. В Django это вообще святое, потому что задачи раскиданы по разным папкам-приложениям, а Celery один на весь проект.

from celery import shared_task  # Импортировал и похуй

@shared_task  # Навесил и забыл. Свободная, блядь, птица.
def add_shared(x, y):
    return x + y

Вот она, красота. Функция add_shared теперь готова служить любому, кто её позовёт. Универсальный солдат, ёпта.

Так когда что использовать, чтобы не вышло как всегда?

  • @shared_task — в 99% случаев, блядь. Особенно в Django или когда пишешь что-то типо библиотеки. Не паришься, импортируешь и всё. Гибко, просто, охуенно.
  • @task — только если ты реально ебанутый и тебе нужно несколько разных Celery-приложений в одном проекте. И чтобы задачи из одного в другое не перетекали, как говно в проруби. Типа у тебя один воркер для срочных задач, другой для долгих, и конфиги у них разные. Вот тогда да, привязывай конкретную задачу к конкретному app. Но это такой высший пилотаж, на грани ебли с ослом.

Короче, если сомневаешься — @shared_task и в пизду. Не прогадаешь. А то начнёшь ебаться с привязками, а в итоге задачи просто не будут запускаться, и будешь сидеть, чесать репу: "Ну что за хуйня?".