|
@@ -216,13 +216,17 @@ class Signature(dict):
|
|
return s
|
|
return s
|
|
partial = clone
|
|
partial = clone
|
|
|
|
|
|
- def freeze(self, _id=None, group_id=None, chord=None, root_id=None):
|
|
|
|
|
|
+ def freeze(self, _id=None, group_id=None, chord=None,
|
|
|
|
+ root_id=None, parent_id=None):
|
|
opts = self.options
|
|
opts = self.options
|
|
try:
|
|
try:
|
|
tid = opts['task_id']
|
|
tid = opts['task_id']
|
|
except KeyError:
|
|
except KeyError:
|
|
tid = opts['task_id'] = _id or uuid()
|
|
tid = opts['task_id'] = _id or uuid()
|
|
- root_id = opts.setdefault('root_id', root_id)
|
|
|
|
|
|
+ if root_id:
|
|
|
|
+ opts['root_id'] = root_id
|
|
|
|
+ if parent_id:
|
|
|
|
+ opts['parent_id'] = parent_id
|
|
if 'reply_to' not in opts:
|
|
if 'reply_to' not in opts:
|
|
opts['reply_to'] = self.app.oid
|
|
opts['reply_to'] = self.app.oid
|
|
if group_id:
|
|
if group_id:
|
|
@@ -251,6 +255,9 @@ class Signature(dict):
|
|
def set_immutable(self, immutable):
|
|
def set_immutable(self, immutable):
|
|
self.immutable = immutable
|
|
self.immutable = immutable
|
|
|
|
|
|
|
|
+ def set_parent_id(self, parent_id):
|
|
|
|
+ self.parent_id = parent_id
|
|
|
|
+
|
|
def apply_async(self, args=(), kwargs={}, route_name=None, **options):
|
|
def apply_async(self, args=(), kwargs={}, route_name=None, **options):
|
|
try:
|
|
try:
|
|
_apply = self._apply_async
|
|
_apply = self._apply_async
|
|
@@ -362,6 +369,8 @@ class Signature(dict):
|
|
except KeyError:
|
|
except KeyError:
|
|
return _partial(self.app.send_task, self['task'])
|
|
return _partial(self.app.send_task, self['task'])
|
|
id = _getitem_property('options.task_id')
|
|
id = _getitem_property('options.task_id')
|
|
|
|
+ parent_id = _getitem_property('options.parent_id')
|
|
|
|
+ root_id = _getitem_property('options.root_id')
|
|
task = _getitem_property('task')
|
|
task = _getitem_property('task')
|
|
args = _getitem_property('args')
|
|
args = _getitem_property('args')
|
|
kwargs = _getitem_property('kwargs')
|
|
kwargs = _getitem_property('kwargs')
|
|
@@ -399,8 +408,8 @@ class chain(Signature):
|
|
dict(self.options, **options) if options else self.options))
|
|
dict(self.options, **options) if options else self.options))
|
|
|
|
|
|
def run(self, args=(), kwargs={}, group_id=None, chord=None,
|
|
def run(self, args=(), kwargs={}, group_id=None, chord=None,
|
|
- task_id=None, link=None, link_error=None,
|
|
|
|
- publisher=None, producer=None, root_id=None, app=None, **options):
|
|
|
|
|
|
+ task_id=None, link=None, link_error=None, publisher=None,
|
|
|
|
+ producer=None, root_id=None, parent_id=None, app=None, **options):
|
|
app = app or self.app
|
|
app = app or self.app
|
|
use_link = self._use_link
|
|
use_link = self._use_link
|
|
args = (tuple(args) + tuple(self.args)
|
|
args = (tuple(args) + tuple(self.args)
|
|
@@ -410,7 +419,7 @@ class chain(Signature):
|
|
tasks, results = self._frozen
|
|
tasks, results = self._frozen
|
|
else:
|
|
else:
|
|
tasks, results = self.prepare_steps(
|
|
tasks, results = self.prepare_steps(
|
|
- args, self.tasks, root_id, link_error, app,
|
|
|
|
|
|
+ args, self.tasks, root_id, parent_id, link_error, app,
|
|
task_id, group_id, chord,
|
|
task_id, group_id, chord,
|
|
)
|
|
)
|
|
|
|
|
|
@@ -422,15 +431,16 @@ class chain(Signature):
|
|
chain=tasks if not use_link else None, **options)
|
|
chain=tasks if not use_link else None, **options)
|
|
return results[0]
|
|
return results[0]
|
|
|
|
|
|
- def freeze(self, _id=None, group_id=None, chord=None, root_id=None):
|
|
|
|
|
|
+ def freeze(self, _id=None, group_id=None, chord=None,
|
|
|
|
+ root_id=None, parent_id=None):
|
|
_, results = self._frozen = self.prepare_steps(
|
|
_, results = self._frozen = self.prepare_steps(
|
|
- self.args, self.tasks, root_id, None,
|
|
|
|
|
|
+ self.args, self.tasks, root_id, parent_id, None,
|
|
self.app, _id, group_id, chord, clone=False,
|
|
self.app, _id, group_id, chord, clone=False,
|
|
)
|
|
)
|
|
return results[-1]
|
|
return results[-1]
|
|
|
|
|
|
def prepare_steps(self, args, tasks,
|
|
def prepare_steps(self, args, tasks,
|
|
- root_id=None, link_error=None, app=None,
|
|
|
|
|
|
+ root_id=None, parent_id=None, link_error=None, app=None,
|
|
last_task_id=None, group_id=None, chord_body=None,
|
|
last_task_id=None, group_id=None, chord_body=None,
|
|
clone=True, from_dict=Signature.from_dict):
|
|
clone=True, from_dict=Signature.from_dict):
|
|
app = app or self.app
|
|
app = app or self.app
|
|
@@ -447,7 +457,8 @@ class chain(Signature):
|
|
steps_pop = steps.pop
|
|
steps_pop = steps.pop
|
|
steps_extend = steps.extend
|
|
steps_extend = steps.extend
|
|
|
|
|
|
- next_step = prev_task = prev_res = None
|
|
|
|
|
|
+ next_step = prev_task = prev_prev_task = None
|
|
|
|
+ prev_res = prev_prev_res = None
|
|
tasks, results = [], []
|
|
tasks, results = [], []
|
|
i = 0
|
|
i = 0
|
|
while steps:
|
|
while steps:
|
|
@@ -469,21 +480,18 @@ class chain(Signature):
|
|
# splice the chain
|
|
# splice the chain
|
|
steps_extend(task.tasks)
|
|
steps_extend(task.tasks)
|
|
continue
|
|
continue
|
|
- elif isinstance(task, group):
|
|
|
|
- if prev_task:
|
|
|
|
- # automatically upgrade group(...) | s to chord(group, s)
|
|
|
|
- try:
|
|
|
|
- next_step = prev_task
|
|
|
|
- # for chords we freeze by pretending it's a normal
|
|
|
|
- # signature instead of a group.
|
|
|
|
- res = Signature.freeze(next_step, root_id=root_id)
|
|
|
|
- task = chord(
|
|
|
|
- task, body=next_step,
|
|
|
|
- task_id=res.task_id, root_id=root_id,
|
|
|
|
- )
|
|
|
|
- except IndexError:
|
|
|
|
- pass # no callback, so keep as group.
|
|
|
|
|
|
|
|
|
|
+ if isinstance(task, group) and prev_task:
|
|
|
|
+ # automatically upgrade group(...) | s to chord(group, s)
|
|
|
|
+ # for chords we freeze by pretending it's a normal
|
|
|
|
+ # signature instead of a group.
|
|
|
|
+ tasks.pop()
|
|
|
|
+ results.pop()
|
|
|
|
+ prev_res = prev_prev_res
|
|
|
|
+ task = chord(
|
|
|
|
+ task, body=prev_task,
|
|
|
|
+ task_id=res.task_id, root_id=root_id, app=app,
|
|
|
|
+ )
|
|
if is_last_task:
|
|
if is_last_task:
|
|
# chain(task_id=id) means task id is set for the last task
|
|
# chain(task_id=id) means task id is set for the last task
|
|
# in the chain. If the chord is part of a chord/group
|
|
# in the chain. If the chord is part of a chord/group
|
|
@@ -496,26 +504,36 @@ class chain(Signature):
|
|
)
|
|
)
|
|
else:
|
|
else:
|
|
res = task.freeze(root_id=root_id)
|
|
res = task.freeze(root_id=root_id)
|
|
- root_id = res.id if root_id is None else root_id
|
|
|
|
|
|
+
|
|
i += 1
|
|
i += 1
|
|
|
|
|
|
if prev_task:
|
|
if prev_task:
|
|
|
|
+ prev_task.set_parent_id(task.id)
|
|
if use_link:
|
|
if use_link:
|
|
# link previous task to this task.
|
|
# link previous task to this task.
|
|
task.link(prev_task)
|
|
task.link(prev_task)
|
|
- if not res.parent:
|
|
|
|
|
|
+ if not res.parent and prev_res:
|
|
prev_res.parent = res.parent
|
|
prev_res.parent = res.parent
|
|
- else:
|
|
|
|
|
|
+ elif prev_res:
|
|
prev_res.parent = res
|
|
prev_res.parent = res
|
|
|
|
|
|
|
|
+ if is_first_task and parent_id is not None:
|
|
|
|
+ task.set_parent_id(parent_id)
|
|
|
|
+
|
|
if link_error:
|
|
if link_error:
|
|
task.set(link_error=link_error)
|
|
task.set(link_error=link_error)
|
|
|
|
|
|
tasks.append(task)
|
|
tasks.append(task)
|
|
results.append(res)
|
|
results.append(res)
|
|
|
|
|
|
- prev_task, prev_res = task, res
|
|
|
|
|
|
+ prev_prev_task, prev_task, prev_prev_res, prev_res = (
|
|
|
|
+ prev_task, task, prev_res, res,
|
|
|
|
+ )
|
|
|
|
|
|
|
|
+ if root_id is None and tasks:
|
|
|
|
+ root_id = tasks[-1].id
|
|
|
|
+ for task in reversed(tasks):
|
|
|
|
+ task.options['root_id'] = root_id
|
|
return tasks, results
|
|
return tasks, results
|
|
|
|
|
|
def apply(self, args=(), kwargs={}, **options):
|
|
def apply(self, args=(), kwargs={}, **options):
|
|
@@ -634,13 +652,16 @@ class chunks(Signature):
|
|
return cls(task, it, n, app=app)()
|
|
return cls(task, it, n, app=app)()
|
|
|
|
|
|
|
|
|
|
-def _maybe_group(tasks):
|
|
|
|
|
|
+def _maybe_group(tasks, app):
|
|
|
|
+ if isinstance(tasks, dict):
|
|
|
|
+ tasks = signature(tasks, app=app)
|
|
|
|
+
|
|
if isinstance(tasks, group):
|
|
if isinstance(tasks, group):
|
|
- tasks = list(tasks.tasks)
|
|
|
|
|
|
+ tasks = tasks.tasks
|
|
elif isinstance(tasks, abstract.CallableSignature):
|
|
elif isinstance(tasks, abstract.CallableSignature):
|
|
tasks = [tasks]
|
|
tasks = [tasks]
|
|
else:
|
|
else:
|
|
- tasks = [signature(t) for t in regen(tasks)]
|
|
|
|
|
|
+ tasks = [signature(t, app=app) for t in regen(tasks)]
|
|
return tasks
|
|
return tasks
|
|
|
|
|
|
|
|
|
|
@@ -649,8 +670,9 @@ class group(Signature):
|
|
tasks = _getitem_property('kwargs.tasks')
|
|
tasks = _getitem_property('kwargs.tasks')
|
|
|
|
|
|
def __init__(self, *tasks, **options):
|
|
def __init__(self, *tasks, **options):
|
|
|
|
+ app = options.get('app')
|
|
if len(tasks) == 1:
|
|
if len(tasks) == 1:
|
|
- tasks = _maybe_group(tasks[0])
|
|
|
|
|
|
+ tasks = _maybe_group(tasks[0], app)
|
|
Signature.__init__(
|
|
Signature.__init__(
|
|
self, 'celery.group', (), {'tasks': tasks}, **options
|
|
self, 'celery.group', (), {'tasks': tasks}, **options
|
|
)
|
|
)
|
|
@@ -662,6 +684,9 @@ class group(Signature):
|
|
d, group(d['kwargs']['tasks'], app=app, **d['options']),
|
|
d, group(d['kwargs']['tasks'], app=app, **d['options']),
|
|
)
|
|
)
|
|
|
|
|
|
|
|
+ def __len__(self):
|
|
|
|
+ return len(self.tasks)
|
|
|
|
+
|
|
def _prepared(self, tasks, partial_args, group_id, root_id, app, dict=dict,
|
|
def _prepared(self, tasks, partial_args, group_id, root_id, app, dict=dict,
|
|
CallableSignature=abstract.CallableSignature,
|
|
CallableSignature=abstract.CallableSignature,
|
|
from_dict=Signature.from_dict):
|
|
from_dict=Signature.from_dict):
|
|
@@ -703,6 +728,10 @@ class group(Signature):
|
|
options.pop('task_id', uuid()))
|
|
options.pop('task_id', uuid()))
|
|
return options, group_id, options.get('root_id')
|
|
return options, group_id, options.get('root_id')
|
|
|
|
|
|
|
|
+ def set_parent_id(self, parent_id):
|
|
|
|
+ for task in self.tasks:
|
|
|
|
+ task.set_parent_id(parent_id)
|
|
|
|
+
|
|
def apply_async(self, args=(), kwargs=None, add_to_parent=True,
|
|
def apply_async(self, args=(), kwargs=None, add_to_parent=True,
|
|
producer=None, **options):
|
|
producer=None, **options):
|
|
app = self.app
|
|
app = self.app
|
|
@@ -757,7 +786,7 @@ class group(Signature):
|
|
def __call__(self, *partial_args, **options):
|
|
def __call__(self, *partial_args, **options):
|
|
return self.apply_async(partial_args, **options)
|
|
return self.apply_async(partial_args, **options)
|
|
|
|
|
|
- def _freeze_unroll(self, new_tasks, group_id, chord, root_id):
|
|
|
|
|
|
+ def _freeze_unroll(self, new_tasks, group_id, chord, root_id, parent_id):
|
|
stack = deque(self.tasks)
|
|
stack = deque(self.tasks)
|
|
while stack:
|
|
while stack:
|
|
task = maybe_signature(stack.popleft(), app=self._app).clone()
|
|
task = maybe_signature(stack.popleft(), app=self._app).clone()
|
|
@@ -766,9 +795,11 @@ class group(Signature):
|
|
else:
|
|
else:
|
|
new_tasks.append(task)
|
|
new_tasks.append(task)
|
|
yield task.freeze(group_id=group_id,
|
|
yield task.freeze(group_id=group_id,
|
|
- chord=chord, root_id=root_id)
|
|
|
|
|
|
+ chord=chord, root_id=root_id,
|
|
|
|
+ parent_id=parent_id)
|
|
|
|
|
|
- def freeze(self, _id=None, group_id=None, chord=None, root_id=None):
|
|
|
|
|
|
+ def freeze(self, _id=None, group_id=None, chord=None,
|
|
|
|
+ root_id=None, parent_id=None):
|
|
opts = self.options
|
|
opts = self.options
|
|
try:
|
|
try:
|
|
gid = opts['task_id']
|
|
gid = opts['task_id']
|
|
@@ -779,11 +810,12 @@ class group(Signature):
|
|
if chord:
|
|
if chord:
|
|
opts['chord'] = chord
|
|
opts['chord'] = chord
|
|
root_id = opts.setdefault('root_id', root_id)
|
|
root_id = opts.setdefault('root_id', root_id)
|
|
|
|
+ parent_id = opts.setdefault('parent_id', parent_id)
|
|
new_tasks = []
|
|
new_tasks = []
|
|
# Need to unroll subgroups early so that chord gets the
|
|
# Need to unroll subgroups early so that chord gets the
|
|
# right result instance for chord_unlock etc.
|
|
# right result instance for chord_unlock etc.
|
|
results = list(self._freeze_unroll(
|
|
results = list(self._freeze_unroll(
|
|
- new_tasks, group_id, chord, root_id,
|
|
|
|
|
|
+ new_tasks, group_id, chord, root_id, parent_id,
|
|
))
|
|
))
|
|
if isinstance(self.tasks, MutableSequence):
|
|
if isinstance(self.tasks, MutableSequence):
|
|
self.tasks[:] = new_tasks
|
|
self.tasks[:] = new_tasks
|
|
@@ -819,16 +851,29 @@ class group(Signature):
|
|
class chord(Signature):
|
|
class chord(Signature):
|
|
|
|
|
|
def __init__(self, header, body=None, task='celery.chord',
|
|
def __init__(self, header, body=None, task='celery.chord',
|
|
- args=(), kwargs={}, **options):
|
|
|
|
|
|
+ args=(), kwargs={}, app=None, **options):
|
|
Signature.__init__(
|
|
Signature.__init__(
|
|
self, task, args,
|
|
self, task, args,
|
|
- dict(kwargs, header=_maybe_group(header),
|
|
|
|
|
|
+ dict(kwargs, header=_maybe_group(header, app),
|
|
body=maybe_signature(body, app=self._app)), **options
|
|
body=maybe_signature(body, app=self._app)), **options
|
|
)
|
|
)
|
|
self.subtask_type = 'chord'
|
|
self.subtask_type = 'chord'
|
|
|
|
|
|
- def freeze(self, *args, **kwargs):
|
|
|
|
- return self.body.freeze(*args, **kwargs)
|
|
|
|
|
|
+ def freeze(self, _id=None, group_id=None, chord=None,
|
|
|
|
+ root_id=None, parent_id=None):
|
|
|
|
+ if not isinstance(self.tasks, group):
|
|
|
|
+ self.tasks = group(self.tasks)
|
|
|
|
+ self.tasks.freeze(parent_id=parent_id, root_id=root_id)
|
|
|
|
+ self.id = self.tasks.id
|
|
|
|
+ return self.body.freeze(_id, parent_id=self.id, root_id=root_id)
|
|
|
|
+
|
|
|
|
+ def set_parent_id(self, parent_id):
|
|
|
|
+ tasks = self.tasks
|
|
|
|
+ if isinstance(tasks, group):
|
|
|
|
+ tasks = tasks.tasks
|
|
|
|
+ for task in tasks:
|
|
|
|
+ task.set_parent_id(parent_id)
|
|
|
|
+ self.parent_id = parent_id
|
|
|
|
|
|
@classmethod
|
|
@classmethod
|
|
def from_dict(self, d, app=None):
|
|
def from_dict(self, d, app=None):
|
|
@@ -848,7 +893,11 @@ class chord(Signature):
|
|
def _get_app(self, body=None):
|
|
def _get_app(self, body=None):
|
|
app = self._app
|
|
app = self._app
|
|
if app is None:
|
|
if app is None:
|
|
- app = self.tasks[0]._app
|
|
|
|
|
|
+ try:
|
|
|
|
+ tasks = self.tasks.tasks # is a group
|
|
|
|
+ except AttributeError:
|
|
|
|
+ tasks = self.tasks
|
|
|
|
+ app = tasks[0]._app
|
|
if app is None and body is not None:
|
|
if app is None and body is not None:
|
|
app = body._app
|
|
app = body._app
|
|
return app if app is not None else current_app
|
|
return app if app is not None else current_app
|
|
@@ -900,6 +949,7 @@ class chord(Signature):
|
|
body.chord_size = self.__length_hint__()
|
|
body.chord_size = self.__length_hint__()
|
|
options = dict(self.options, **options) if options else self.options
|
|
options = dict(self.options, **options) if options else self.options
|
|
if options:
|
|
if options:
|
|
|
|
+ options.pop('task_id', None)
|
|
body.options.update(options)
|
|
body.options.update(options)
|
|
|
|
|
|
results = header.freeze(
|
|
results = header.freeze(
|