Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
87dcf25
ref(o11y): Support SDK configured with the streaming trace lifecycle
alexander-alderman-webb Jul 21, 2026
99ff2de
python lint
alexander-alderman-webb Jul 21, 2026
6c06b23
make mypy happy
alexander-alderman-webb Jul 21, 2026
43bd7ee
add missing declaration
alexander-alderman-webb Jul 21, 2026
1e90734
test: Initialize SDK in relevant tests
alexander-alderman-webb Jul 21, 2026
5de3e0d
remove dead code
alexander-alderman-webb Jul 21, 2026
d570be1
ref(o11y): Remove redundant span status assignment
alexander-alderman-webb Jul 21, 2026
a78e920
merge
alexander-alderman-webb Jul 21, 2026
283096b
add pytest parametrization
alexander-alderman-webb Jul 21, 2026
49883c8
move fixtures after mocks
alexander-alderman-webb Jul 21, 2026
d6ea809
remove sentry_init from frequency test
alexander-alderman-webb Jul 21, 2026
9c64fa8
configure sdk to avoid sleeps
alexander-alderman-webb Jul 21, 2026
0268df0
Merge branch 'webb/add-init-to-tests' into webb/remove-explicit-status
alexander-alderman-webb Jul 21, 2026
ea6dba3
fix import ordering problem
alexander-alderman-webb Jul 21, 2026
32fd19d
cleanup in fixture
alexander-alderman-webb Jul 21, 2026
43ec0e3
Merge branch 'webb/add-init-to-tests' into webb/remove-explicit-status
alexander-alderman-webb Jul 21, 2026
cb29166
merge
alexander-alderman-webb Jul 21, 2026
265e126
remove unused parameter
alexander-alderman-webb Jul 21, 2026
2b52bbc
simplify transport
alexander-alderman-webb Jul 21, 2026
6f7f6a4
Merge branch 'webb/add-init-to-tests' into webb/remove-explicit-status
alexander-alderman-webb Jul 21, 2026
9c4f63f
Merge branch 'webb/remove-explicit-status' into webb/streaming-trace-…
alexander-alderman-webb Jul 21, 2026
71deb34
add attributes in streaming path
alexander-alderman-webb Jul 21, 2026
bf93e3c
use consistent argument style
alexander-alderman-webb Jul 21, 2026
084b3a1
create span only in isolation scope
alexander-alderman-webb Jul 21, 2026
aad2d46
add namespace to attributes
alexander-alderman-webb Jul 21, 2026
530308a
Equivalent changes in taskbroker_client
alexander-alderman-webb Jul 22, 2026
ce10118
update tests
alexander-alderman-webb Jul 22, 2026
35831f8
revert test changes
alexander-alderman-webb Jul 22, 2026
3c0b840
remove test additions
alexander-alderman-webb Jul 22, 2026
d2cae9c
create shim in sdk.py
alexander-alderman-webb Jul 22, 2026
aca4959
address bots
alexander-alderman-webb Jul 22, 2026
8272c9f
remove stray argument
alexander-alderman-webb Jul 22, 2026
cd8c9d4
early return in start_span
alexander-alderman-webb Jul 22, 2026
fd46b19
move attributes into shim
alexander-alderman-webb Jul 23, 2026
106634c
bump sentry-sdk to when span streaming is fully available
alexander-alderman-webb Jul 23, 2026
6b478e6
use greater than or equal
alexander-alderman-webb Jul 23, 2026
213edcd
Merge branch 'main' into webb/streaming-trace-lifecycle
alexander-alderman-webb Jul 23, 2026
7770df5
do not add args and kwargs attributes to StreamedSpan
alexander-alderman-webb Jul 23, 2026
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
2 changes: 1 addition & 1 deletion clients/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "Taskbroker python client and worker runtime"
readme = "README.md"
dependencies = [
"sentry-arroyo>=2.41.0",
"sentry-sdk[http2]>=2.43.0",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should bump the minimum to the latest, so Span Streaming is fully available.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this is a library, we should not arbitrarily restrict its version ranges unless actually required

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It is required, hence I raised it 😄

@alexander-alderman-webb alexander-alderman-webb Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Bumped 106634c / 6b478e6

"sentry-sdk[http2]>=2.66.1",
"sentry-protos>=0.26.1",
"confluent_kafka>=2.3.0",
"cronsim>=2.6",
Expand Down
17 changes: 9 additions & 8 deletions clients/python/src/taskbroker_client/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from concurrent import futures
from typing import Any, cast

import sentry_sdk
from arroyo.backends.kafka import KafkaPayload
from arroyo.types import BrokerValue, Topic
from sentry_protos.taskbroker.v1.taskbroker_pb2 import TaskActivation
Expand All @@ -20,6 +19,7 @@
from taskbroker_client.metrics import MetricsBackend
from taskbroker_client.retry import Retry
from taskbroker_client.router import TaskRouter
from taskbroker_client.sdk import start_span
from taskbroker_client.task import ExternalTask, P, R, Task
from taskbroker_client.types import ContextHook, ProducerFactory, ProducerProtocol

Expand Down Expand Up @@ -172,15 +172,16 @@ def send_task(
) -> ProducerFuture:
topic = self.topic

with sentry_sdk.start_span(
op=OP.QUEUE_PUBLISH,
with start_span(
name=activation.taskname,
op=OP.QUEUE_PUBLISH,
origin="taskworker",
) as span:
span.set_data(SPANDATA.MESSAGING_DESTINATION_NAME, activation.namespace)
span.set_data(SPANDATA.MESSAGING_MESSAGE_ID, activation.id)
span.set_data(SPANDATA.MESSAGING_SYSTEM, "taskworker")

attributes={
SPANDATA.MESSAGING_DESTINATION_NAME: activation.namespace,
SPANDATA.MESSAGING_MESSAGE_ID: activation.id,
SPANDATA.MESSAGING_SYSTEM: "taskworker",
},
):
produce_future = self._producer(topic).produce(
Topic(name=topic),
KafkaPayload(key=None, value=activation.SerializeToString(), headers=[]),
Expand Down
82 changes: 82 additions & 0 deletions clients/python/src/taskbroker_client/sdk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from contextlib import nullcontext
from typing import Any, ContextManager

import sentry_sdk
from sentry_sdk.scope import Scope
from sentry_sdk.traces import StreamedSpan
from sentry_sdk.tracing import NoOpSpan, Span, Transaction
from sentry_sdk.tracing_utils import has_span_streaming_enabled


def start_transaction(
name: str,
op: str,
origin: str,
attributes: dict[str, Any],
headers: dict[str, Any],
sampling_context: dict[str, Any],
) -> Transaction | NoOpSpan | StreamedSpan | ContextManager[Any]:
"""Start a transaction, or a span if span streaming is enabled."""
span = None
try:
is_span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
if is_span_streaming:
sentry_sdk.traces.continue_trace(headers)
Comment thread
sentry[bot] marked this conversation as resolved.
Scope.set_custom_sampling_context(sampling_context)

return sentry_sdk.traces.start_span(
name=name,
attributes={
"sentry.op": op,
"sentry.origin": origin,
**attributes,
},
)
Comment thread
cursor[bot] marked this conversation as resolved.

transaction = sentry_sdk.continue_trace(
environ_or_headers=headers,
op=op,
name=name,
origin=origin,
)

span = sentry_sdk.start_transaction(transaction, custom_sampling_context=sampling_context)
for key, value in attributes.items():
span.set_data(key, value)
except Exception:
pass

if span is None:
return nullcontext()
Comment thread
alexander-alderman-webb marked this conversation as resolved.
return span
Comment thread
alexander-alderman-webb marked this conversation as resolved.


def start_span(
name: str, op: str, origin: str, attributes: dict[str, Any]
) -> Span | StreamedSpan | ContextManager[Any]:
"""Start a span in the currently active trace lifecycle."""
try:
is_span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options)
if is_span_streaming:
return sentry_sdk.traces.start_span(
name=name,
attributes={
"sentry.op": op,
"sentry.origin": origin,
**attributes,
},
)
Comment thread
alexander-alderman-webb marked this conversation as resolved.

span = sentry_sdk.start_span(
op=op,
name=name,
origin=origin,
)
for key, value in attributes.items():
span.set_data(key, value)

return span
except Exception:
pass

return nullcontext()
58 changes: 32 additions & 26 deletions clients/python/src/taskbroker_client/worker/workerchild.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
)
from sentry_sdk.consts import OP, SPANDATA
from sentry_sdk.crons import MonitorStatus, capture_checkin
from sentry_sdk.tracing import Span

from taskbroker_client.app import import_app
from taskbroker_client.constants import CompressionType
from taskbroker_client.retry import NoRetriesRemainingError
from taskbroker_client.sdk import start_span, start_transaction
from taskbroker_client.state import clear_current_task, current_task, set_current_task
from taskbroker_client.task import Task
from taskbroker_client.types import ContextHook, InflightTaskActivation, ProcessingResult
Expand Down Expand Up @@ -612,45 +614,49 @@ def _execute_activation(
kwargs = parameters.get("kwargs", {})

headers = dict(activation.headers)
transaction = sentry_sdk.continue_trace(
environ_or_headers=headers,
op="queue.task.taskworker",
name=activation.taskname,
origin="taskworker",
)
sampling_context = {
"taskworker": {
"task": activation.taskname,
}
}

with (
metrics.track_memory_usage(
"taskworker.worker.memory_change",
tags={"namespace": activation.namespace, "taskname": activation.taskname},
),
sentry_sdk.isolation_scope(),
sentry_sdk.start_transaction(transaction, custom_sampling_context=sampling_context),
start_transaction(
name=activation.taskname,
op="queue.task.taskworker",
origin="taskworker",
attributes={
"taskworker-task.id": activation.id,
},
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
alexander-alderman-webb marked this conversation as resolved.
headers=headers,
sampling_context={
"taskworker": {
"task": activation.taskname,
}
},
) as transaction,
):
transaction.set_data(
"taskworker-task", {"args": args, "kwargs": kwargs, "id": activation.id}
)
# Do not attach on StreamedSpan because eager serialization increases memory use.
if isinstance(transaction, Span):
transaction.set_data("taskworker-task.args", args)
transaction.set_data("taskworker-task.kwargs", kwargs)

task_added_time = activation.received_at.ToDatetime().timestamp()
# latency attribute needs to be in milliseconds
latency = (time.time() - task_added_time) * 1000

with sentry_sdk.start_span(
op=OP.QUEUE_PROCESS,
with start_span(
name=activation.taskname,
op=OP.QUEUE_PROCESS,
origin="taskworker",
) as span:
span.set_data(SPANDATA.MESSAGING_DESTINATION_NAME, activation.namespace)
span.set_data(SPANDATA.MESSAGING_MESSAGE_ID, activation.id)
span.set_data(SPANDATA.MESSAGING_MESSAGE_RECEIVE_LATENCY, latency)
span.set_data(
SPANDATA.MESSAGING_MESSAGE_RETRY_COUNT, activation.retry_state.attempts
)
span.set_data(SPANDATA.MESSAGING_SYSTEM, "taskworker")

attributes={
SPANDATA.MESSAGING_DESTINATION_NAME: activation.namespace,
SPANDATA.MESSAGING_MESSAGE_ID: activation.id,
SPANDATA.MESSAGING_MESSAGE_RECEIVE_LATENCY: latency,
SPANDATA.MESSAGING_MESSAGE_RETRY_COUNT: activation.retry_state.attempts,
SPANDATA.MESSAGING_SYSTEM: "taskworker",
},
):
# TODO(taskworker) remove this when doing cleanup
# The `__start_time` parameter is spliced into task parameters by
# sentry.celery.SentryTask._add_metadata and needs to be removed
Expand Down
6 changes: 3 additions & 3 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading