Skip to content

Commit 14a8cc8

Browse files
committed
Handle chords correctly and include test.
Groups and chords weren't introduced until Huey 3.0, so handle that gracefully.
1 parent b16696b commit 14a8cc8

2 files changed

Lines changed: 89 additions & 11 deletions

File tree

sentry_sdk/integrations/huey.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,17 @@
3030

3131
try:
3232
from huey.api import Huey, PeriodicTask, Result, ResultGroup, Task
33-
from huey.api import group as HueyGroup
3433
from huey.exceptions import CancelExecution, RetryTask, TaskLockedException
3534
except ImportError:
3635
raise DidNotEnable("Huey is not installed")
3736

37+
try:
38+
from huey.api import chord as HueyChord
39+
from huey.api import group as HueyGroup
40+
except ImportError:
41+
HueyChord = None
42+
HueyGroup = None
43+
3844

3945
HUEY_CONTROL_FLOW_EXCEPTIONS = (CancelExecution, RetryTask, TaskLockedException)
4046

@@ -54,22 +60,32 @@ def patch_enqueue() -> None:
5460

5561
@ensure_integration_enabled(HueyIntegration, old_enqueue)
5662
def _sentry_enqueue(
57-
self: "Huey", item: "Union[Task, HueyGroup]"
63+
self: "Huey", item: "Union[Task, HueyGroup, HueyChord]"
5864
) -> "Optional[Union[Result, ResultGroup]]":
59-
span_name = "Huey Task Group" if type(item) is HueyGroup else item.name
65+
if HueyChord is not None and isinstance(item, HueyChord):
66+
span_name = "Huey Chord"
67+
elif HueyGroup is not None and isinstance(item, HueyGroup):
68+
span_name = "Huey Task Group"
69+
else:
70+
span_name = item.name
71+
6072
with sentry_sdk.start_span(
6173
op=OP.QUEUE_SUBMIT_HUEY,
6274
name=span_name,
6375
origin=HueyIntegration.origin,
6476
):
65-
if not isinstance(item, PeriodicTask) and not isinstance(item, HueyGroup):
77+
if (
78+
not isinstance(item, PeriodicTask)
79+
and not (HueyGroup is not None and isinstance(item, HueyGroup))
80+
and not (HueyChord is not None and isinstance(item, HueyChord))
81+
):
6682
# Attach trace propagation data to task kwargs. We do
6783
# not do this for periodic tasks, as these don't
6884
# really have an originating transaction.
69-
# Additionally, we do not do this for Huey groups, as enqueue will
70-
# recursively call this method for each task within the group, resulting
71-
# in the trace propagation data being attached to each task individually (
72-
# which we want)
85+
# Additionally, we do not do this for Huey groups or chords, as enqueue will
86+
# recursively call this method for each task within the list, resulting
87+
# in the trace propagation data being attached to each task individually
88+
# (which we want)
7389
item.kwargs["sentry_headers"] = {
7490
BAGGAGE_HEADER_NAME: get_baggage(),
7591
SENTRY_TRACE_HEADER_NAME: get_traceparent(),

tests/integrations/huey/test_huey.py

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import pytest
44
from huey import __version__ as HUEY_VERSION
5-
from huey import group
65
from huey.api import MemoryHuey, Result
76
from huey.exceptions import RetryTask
87

@@ -12,6 +11,11 @@
1211

1312
HUEY_VERSION = parse_version(HUEY_VERSION)
1413

14+
try:
15+
from huey.api import chord, group
16+
except ImportError:
17+
chord = None
18+
group = None
1519

1620
@pytest.fixture
1721
def init_huey(sentry_init):
@@ -225,6 +229,7 @@ def propagated_trace_task():
225229
assert event["contexts"]["trace"]["origin"] == "auto.queue.huey"
226230

227231

232+
@pytest.mark.skipif(HUEY_VERSION < (3, 0), reason="group was added in 3.0")
228233
def test_huey_enqueue_group(init_huey, capture_events):
229234
huey = init_huey()
230235

@@ -263,8 +268,65 @@ def task2():
263268
assert spans[2]["description"] == "task2"
264269

265270
# Consumer transaction assertions (one per task)
266-
consumer_events = sorted(events[1:], key=lambda e: e["transaction"])
267-
for i, (consumer_event, expected_name) in enumerate(
271+
consumer_events = events[1:]
272+
for _, (consumer_event, expected_name) in enumerate(
273+
zip(consumer_events, ["task1", "task2"])
274+
):
275+
assert consumer_event["type"] == "transaction"
276+
assert consumer_event["transaction"] == expected_name
277+
assert consumer_event["transaction_info"] == {"source": "task"}
278+
assert consumer_event["contexts"]["trace"]["op"] == "queue.task.huey"
279+
assert consumer_event["contexts"]["trace"]["origin"] == "auto.queue.huey"
280+
assert consumer_event["contexts"]["trace"]["status"] == "ok"
281+
assert consumer_event["contexts"]["trace"]["trace_id"] == transaction.trace_id
282+
assert "huey_task_id" in consumer_event["tags"]
283+
assert consumer_event["tags"]["huey_task_retry"] is False
284+
285+
286+
@pytest.mark.skipif(HUEY_VERSION < (3, 0), reason="chord was added in 3.0")
287+
def test_huey_enqueue_chord(init_huey, capture_events):
288+
huey = init_huey()
289+
290+
events = capture_events()
291+
292+
@huey.task()
293+
def task1():
294+
pass
295+
296+
@huey.task()
297+
def task2(results):
298+
pass
299+
300+
with start_transaction() as transaction:
301+
huey.enqueue(chord([task1.s()], task2.s()))
302+
303+
for _ in range(2):
304+
task = huey.dequeue()
305+
huey.execute(task)
306+
307+
assert len(events) == 3
308+
309+
# Enqueue spans
310+
producer_event = events[0]
311+
assert producer_event["contexts"]["trace"]["trace_id"] == transaction.trace_id
312+
assert producer_event["contexts"]["trace"]["origin"] == "manual"
313+
314+
spans = producer_event["spans"]
315+
assert len(spans) == 2
316+
assert spans[0]["op"] == "queue.submit.huey"
317+
assert spans[0]["description"] == "Huey Chord"
318+
assert spans[1]["op"] == "queue.submit.huey"
319+
assert spans[1]["description"] == "task1"
320+
321+
task1_event = events[1]
322+
# Confirm the first task enqueued the chord callback
323+
task1_spans = task1_event["spans"]
324+
assert len(task1_spans) == 1
325+
assert task1_spans[0]["op"] == "queue.submit.huey"
326+
assert task1_spans[0]["description"] == "task2"
327+
328+
consumer_events = events[1:]
329+
for _, (consumer_event, expected_name) in enumerate(
268330
zip(consumer_events, ["task1", "task2"])
269331
):
270332
assert consumer_event["type"] == "transaction"

0 commit comments

Comments
 (0)