27

Python 3.x, Celery 4.x...

I have a class-based task.

myproj/celery.py

from celery import Celery

# django settings stuff...

app = Celery('myproj')
app.autodiscover_tasks()

app1/tasks.py

import celery

class EmailTask(celery.Task):
    def run(self, *args, **kwargs):
        self.do_something()

If I do:

$ celery worker -A myproj -l info
[tasks]
  . app2.tasks.debug_task
  . app2.tasks.test

So, the celery decorators work to register tasks, but the class-based task is not registered.

How do I get the class-based tasks to register?

Update 1:

If I add the following lines to app1/tasks.py

from myproj.celery import app
email_task = app.tasks[EmailTask.name]

.

$ celery worker -A myproj -l info
  File "myproj/app1/tasks.py", line 405, in <module>
    email_task = app.tasks[EmailTask.name]
  File "/usr/local/lib/python3.5/site-packages/celery/app/registry.py", line 19, in __missing__
    raise self.NotRegistered(key)
celery.exceptions.NotRegistered

Update 2:

I am able to execute my task synchronously (run) via a wrapper. However, I cannot run the task async, i.e., via delay.

app1/tasks.py

@app.task
def email_task():
    """
    Wrapper to call class based task
    """
    task = EmailTask()
    # task.delay()  # Won't work!!!
    task.run()

.

$./manage.py shell
> from app1.tasks import EmailTask
> task1 = EmailTask()
> task1.run() # a-okay
> task2 = EmailTask()
> task2.delay() # nope
  <AsyncResult: 1c03bad9-169a-4a4e-a56f-7d83892e8bbc>

# And on the worker...
[2017-01-22 08:07:28,120: INFO/PoolWorker-1] Task app1.tasks.email_task[41e5bc7d-058a-400e-9f73-c853c0f60a2a] succeeded in 0.0701281649817247s: None
[2017-01-22 08:10:31,909: ERROR/MainProcess] Received unregistered task of type None.
The message has been ignored and discarded.
James
  • 2,488
  • 2
  • 28
  • 45

3 Answers3

30

You can find full description here, but for me it was enough to add

from myapp.celery import app
app.tasks.register(MyTaskTask())
Oleksandr Dashkov
  • 2,249
  • 1
  • 15
  • 29
22

With celery==4.2.1 I had to use the return value of Celery.register_task() as the task instance to call delay() on:

# my_app/tasks.py
import celery

from my_app.celery import app

class MyTask(celery.Task):
    def run(self):
        [...]

MyTask = app.register_task(MyTask())

Then to use it:

# my_app/app.py
from my_app.tasks import MyTask

[...]

MyTask.delay()

The solution was described in a Github issue and is documented here.

Hth, dtk

the_drow
  • 18,571
  • 25
  • 126
  • 193
dtk
  • 2,197
  • 2
  • 26
  • 19
0

I just spent a long time figuring out why my worker was crashing when I started it.

if you are receiving:
AttributeError: 'NoneType' object has no attribute 'push'
when you start your worker

do NOT use
app.tasks.register(MyTask())

instead use:
app.register_task(MyTask())

see more here: https://github.com/celery/celery/issues/7173

Note - this was done on celery 5.3.0

dafrandle
  • 78
  • 1
  • 8