From 7178c07658b74770b4047175ae583f207295b29a Mon Sep 17 00:00:00 2001 From: maybe-sybr <58414429+maybe-sybr@users.noreply.github.com> Date: Fri, 18 Sep 2020 14:23:40 +1000 Subject: [PATCH] fix: Retain `group_id` when tasks get re-frozen When a group task which is part of a chain was to be delayed by `trace_task()`, it would be reconstructed from the serialized request. Normally, this sets the `group_id` of encapsulated tasks to the ID of the group being instantiated. However, in the specific situation of a group that is the last task in a chain which contributes to the completion of a chord, it is essential that the group ID of the top-most group is used instead. This top-most group ID is used by the redis backend to track the completions of "final elements" of a chord in the `on_chord_part_return()` implementation. By overwriting the group ID which was already set in the `options` dictionaries of the child tasks being deserialized, the chord accounting done by the redis backend would be made inaccurate and chords would never complete. This change alters how options are overridden for signatures to ensure that if a `group_id` has already been set, it cannot be overridden. Since group ID should be generally opaque to users, this should not be disruptive. --- celery/canvas.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/celery/canvas.py b/celery/canvas.py index 7871f7b395d..ccd7dc15d98 100644 --- a/celery/canvas.py +++ b/celery/canvas.py @@ -227,8 +227,7 @@ def _merge(self, args=None, kwargs=None, options=None, force=False): options = options if options else {} if self.immutable and not force: return (self.args, self.kwargs, - dict(self.options, - **options) if options else self.options) + dict(options, **self.options) if options else self.options) return (tuple(args) + tuple(self.args) if args else self.args, dict(self.kwargs, **kwargs) if kwargs else self.kwargs, dict(self.options, **options) if options else self.options) @@ -286,7 +285,7 @@ def freeze(self, _id=None, group_id=None, chord=None, opts['parent_id'] = parent_id if 'reply_to' not in opts: opts['reply_to'] = self.app.oid - if group_id: + if group_id and "group_id" not in opts: opts['group_id'] = group_id if chord: opts['chord'] = chord