@@ -39,40 +39,55 @@ def tags_from_context(context):
3939 return tags
4040
4141
42- def attach_span (task , task_id , span ):
42+ def attach_span (task , task_id , span , is_publish = False ):
4343 """Helper to propagate a `Span` for the given `Task` instance. This
4444 function uses a `WeakValueDictionary` that stores a Datadog Span using
45- the `task_id` as a key. This is useful when information must be
45+ the `( task_id, is_publish) ` as a key. This is useful when information must be
4646 propagated from one Celery signal to another.
47+
48+ DEV: We use (task_id, is_publish) for the key to ensure that publishing a
49+ task from within another task does not cause any conflicts.
50+
51+ This mostly happens when either a task fails and a retry policy is in place,
52+ or when a task is manually retries (e.g. `task.retry()`), we end up trying
53+ to publish a task with the same id as the task currently running.
54+
55+ Previously publishing the new task would overwrite the existing `celery.run` span
56+ in the `weak_dict` causing that span to be forgotten and never finished.
57+
58+ NOTE: We cannot test for this well yet, because we do not run a celery worker,
59+ and cannot run `task.apply_async()`
4760 """
4861 weak_dict = getattr (task , CTX_KEY , None )
4962 if weak_dict is None :
5063 weak_dict = WeakValueDictionary ()
5164 setattr (task , CTX_KEY , weak_dict )
5265
53- weak_dict [task_id ] = span
66+ weak_dict [( task_id , is_publish ) ] = span
5467
5568
56- def detach_span (task , task_id ):
69+ def detach_span (task , task_id , is_publish = False ):
5770 """Helper to remove a `Span` in a Celery task when it's propagated.
5871 This function handles tasks where the `Span` is not attached.
5972 """
6073 weak_dict = getattr (task , CTX_KEY , None )
6174 if weak_dict is None :
6275 return
6376
64- weak_dict .pop (task_id , None )
77+ # DEV: See note in `attach_span` for key info
78+ weak_dict .pop ((task_id , is_publish ), None )
6579
6680
67- def retrieve_span (task , task_id ):
81+ def retrieve_span (task , task_id , is_publish = False ):
6882 """Helper to retrieve an active `Span` stored in a `Task`
6983 instance
7084 """
7185 weak_dict = getattr (task , CTX_KEY , None )
7286 if weak_dict is None :
7387 return
7488 else :
75- return weak_dict .get (task_id )
89+ # DEV: See note in `attach_span` for key info
90+ return weak_dict .get ((task_id , is_publish ))
7691
7792
7893def retrieve_task_id (context ):
0 commit comments