Skip to content

[celery] Celery error callback behavior #13812

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions tests/contrib/celery/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,65 @@ def fn_task():

assert run_span.service == "task-queue"

def test_trace_with_task_error(self):
"""
Test demonstrating the current behavior of the on_error callback.
When calling on_error, the subsequent error task is not traced.
When calling the "error task" directly, it is traced.
"""
error_callback = False

@self.app.task
def fn_task():
raise ValueError("Task failed")

@self.app.task
def err_task(task, err, tb):
nonlocal error_callback
span = self.tracer.start_span("err_task_custom_span")
error_callback = True
span.finish()
return "error happened"

t = fn_task.s().on_error(err_task.s()).delay()
try:
t.get(timeout=self.ASYNC_GET_TIMEOUT)
except ValueError:
pass
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Code Quality Violation

silent exception (...read more)

Using the pass statement in an exception block ignores the exception. Exceptions should never be ignored. Instead, the user must add code to notify an exception occurred and attempt to handle it or recover from it.

The exception to this rule is the use of StopIteration or StopAsyncIteration when implementing a custom iterator (as those errors are used to acknowledge the end of a successful iteration).

View in Datadog  Leave us feedback  Documentation


assert error_callback is True
traces = self.pop_traces()
assert len(traces) == 3
span1 = traces[0][0]
span2 = traces[1][0]
span3 = traces[2][0]
assert span1.name == "celery.apply"
assert span1.error == 0
# Span 2 is just the custom span
assert span2.name == "err_task_custom_span"
assert span2.error == 0
assert span3.name == "celery.run"
assert span3.error == 1
assert span3.resource == "tests.contrib.celery.test_integration.fn_task"
assert span3.get_tag("error.type") == "builtins.ValueError"

# If the error task is called directly, it gets traced.
t2 = err_task.s("task_1", "ValueError: Bad task", "traceback_info").delay()
assert t2.get(timeout=self.ASYNC_GET_TIMEOUT) == "error happened"
traces = self.pop_traces()
assert len(traces) == 3
span1 = traces[0][0]
span2 = traces[1][0]
span3 = traces[2][0]
assert span1.name == "celery.apply"
assert span1.error == 0
assert span2.name == "err_task_custom_span"
assert span2.error == 0
assert span3.name == "celery.run"
assert span3.error == 0
assert span3.resource == "tests.contrib.celery.test_integration.err_task"
assert span3.get_tag("error.type") is None

def test_trace_in_task(self):
@self.app.task
def fn_task():
Expand Down
Loading