Search code examples
pythondjangocelerydjango-celery

celery task decorator throws "TypeError: 'Module object is not callable"


I'm trying desperately to get Celery to play nicely with Django, but to no avail. I am getting tripped up on the following:

project/settings.py:

...

import djcelery
djcelery.setup_loader()

BROKER_URL = 'django://'
CELERY_RESULT_BACKEND = 'django://'
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ENABLE_UTC = True

...

app/tasks.py:

from celery.task import task

@task()
def scheduled_task(param1, param2):
    ...
    return something

Calling scheduled_task(param1, param2) directly (without the decorator) works as expected. However when adding the decorator and firing up the 'development' celery worker like so:

python manage.py celery worker --loglevel=info

...I get the following error:

TypeError: 'module' object is not callable

I've pinned this down to the @task decorator. Every combination I try fails, including:

from celery import task
from celery.task import task
from celery.task.base import task

@task
@task()
@task.task
@task.task()
@celery.task
@celery.task()

Nothing seems to make any difference to the call stack in the exception, they all appear to think that task is a module, and not callable! To make things even more frustrating:

>>> from celery.task import task
>>> task
<function task at 0x10aa2a758>

That sure looks callable to me! Any idea what might be happening? If I've missed anything, I'm happy to post additional logs, files or clarify anything else.


Solution

  • (Converted to an answer from comments)

    From the stack trace I take it that the line return backend(app=self, url=url) is where the exception happens.

    So whatever backend is, it doesn't seem to be a callable. I would try to set a pdb breakpoint in that file (celery/app/base.py) by wrapping that line in

    try:
        backend(app=self, url=url)
    except:
        import pdb; pdb.set_trace(),
    

    and then inspecting backend, and moving up the stack (u command in pdb, d to go down again, w to display call stack) to debug where it all goes wrong.

    The celery docs also mention this:

    How do I import the task decorator?

    The task decorator is available on your Celery instance, if you don’t know what that is then please read First Steps with Celery.

    If you’re using Django or are still using the “old” module based celery API, then you can import the task decorator like this:

    from celery import task
    
    @task
    def add(x, y):
        return x + y
    

    So that should clear up any amiguity about what way to import the task decorator is the right one.