简体   繁体   中英

Celery: How to ignore task result in chord or chain?

I'm using celery, I have several tasks which needed to be executed in order.

For example I have this task:

@celery.task
def tprint(word):
    print word

And I want to do something like this:

>>> chain(tprint.s('a') | tprint.s('b'))()

Then I get TypeError: tprint() takes exactly 1 argument (2 given) .

The same with chord, in this situation which I need a task to be executed after a group of tasks:

>>> chord([tprint.s('a'), tprint.s('b')])(tprint.s('c'))

So how to deal with this situation? I don't care the result of each task, but they need to be executed in order.


Add a second parameter won't work:

@celery.task
def tprint(word, ignore=None):
    print word

>>> chain(tprint.s('a', 0) | tprint.s('b'))()

This will print out 'a' and 'None'.

There is a built-in functionality to ignore result in chaining and others - immutable subtask. You can use .si() shortcut instead of .s() or .subtask(immutable=True)

More details here: http://docs.celeryproject.org/en/master/userguide/canvas.html#immutability

One possible solution has already posted, but I'd like to add further clarification and an alternate solution (and in some cases a superior one).

The error you're seeing, which indicates that your task's signature needs to take into account a second parameter, is due to the fact that when calling tasks in a chain , Celery automatically pushes each tasks result as the first parameter of the following task.

From the docs:

Tasks can be linked together, which in practice means adding a callback task:

>>> res = add.apply_async((2, 2), link=mul.s(16))
>>> res.get()
4

The linked task will be applied with the result of its parent task as the first argument

Therefore, in your case, you could rewrite your task like this:

@celery.task
def tprint(result, word):
    print word

If you're not going to do anything with the result, you may as well ignore it, by changing the decorator thus :

 
 
 
 
  
  
  @celery.task(ignore_result=True)
 
 
  

And then you won't have to change your task signature.

Sorry, that last point needs further research.

You can try doing something like this. Instead of having a single parameter for function tprint you can have 2 parameters

def tprint(word, x=None):
    print word

then

chain(tprint.s('a', 0) | tprint.s('b'))()

Finally find a workaround for this, a chain decorator will do this job.

I don't know how exactly celery did it, but celery seems force bind previous task's result to next task's first argument.

So here's an example:

def chain_deco(func):

    @functools.wraps(func)
    def wrapper(chain=None, *args, **kwargs):
        if chain is False:
            return False

        func(*args, **kwargs)
        return True

    return wrapper


@celery.task
@chain_deco
def hello(word):
    print "hello %s" % word

Now this will give the right output.

>>> (hello.s(word='a') | hello.s(word='b'))()

OR

>>> (hello.s('a') | hello.s('b'))(True)

And decorator also provide the ability to stop a chain in the middle(make the later cascade fail.)

The same mechanism should work for chord too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM