Skip to content

Commit 6d51442

Browse files
cyntwang99claude
andcommitted
fix(tasks): drop StatsD active gauge, keep concurrency OTel-only
A process-local gauge is wrong under multiple workers: DogStatsD gauges are last-write-wins per flush, so N workers emitting their own counts make the metric flap between workers instead of summing to true concurrency. Remove the StatsD active gauge and its bookkeeping; the OTel UpDownCounter already sums correctly across per-instance series and remains the sole concurrency source. The additive StatsD emits (opened/closed counters, duration, stall) aggregate correctly across workers and are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 5a3541a commit 6d51442

2 files changed

Lines changed: 12 additions & 24 deletions

File tree

agentex/src/utils/stream_metrics.py

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,6 @@
6262
_stall_counter: Counter | None = None
6363
_instruments_initialized = False
6464

65-
# Process-local count of currently-open streams, used solely to emit the StatsD
66-
# ``active`` gauge as an absolute value. DogStatsD gauges are last-value-wins and
67-
# do not honor deltas (unlike Etsy StatsD); increment/decrement would instead
68-
# submit a COUNT — the rate of change — never the concurrency level. So the
69-
# StatsD path keeps the running total here and reports it via ``statsd.gauge``.
70-
# The OTel ``UpDownCounter`` expresses this natively and needs no bookkeeping.
71-
_active_stream_count = 0
72-
7365

7466
def _ensure_instruments() -> None:
7567
"""Create the OTel instruments on first use. No-op if OTel is not configured."""
@@ -119,7 +111,6 @@ def record_stream_opened() -> None:
119111
Pair every call with exactly one ``record_stream_closed`` so the active gauge
120112
stays balanced. Never raises: see ``record_stream_closed``.
121113
"""
122-
global _active_stream_count
123114
try:
124115
_ensure_instruments()
125116

@@ -130,9 +121,11 @@ def record_stream_opened() -> None:
130121

131122
if _STATSD_ENABLED:
132123
statsd.increment("agentex.task_stream.opened")
133-
# Report the concurrency level as an absolute gauge, not a delta.
134-
_active_stream_count += 1
135-
statsd.gauge("agentex.task_stream.active", _active_stream_count)
124+
# No StatsD "active" gauge: concurrency is OTel-only. DogStatsD
125+
# gauges are last-write-wins per flush, so N workers each emitting a
126+
# process-local count would make the gauge flap between workers
127+
# rather than sum to the true concurrency. The OTel UpDownCounter
128+
# sums correctly across per-instance series at query time.
136129
except Exception:
137130
logger.debug("Failed to emit agentex.task_stream.opened metric", exc_info=True)
138131

@@ -149,7 +142,6 @@ def record_stream_closed(outcome: StreamOutcome, duration_seconds: float) -> Non
149142
Never raises: emission failures (e.g. a StatsD UDP socket error or an OTel
150143
SDK fault) are swallowed so instrumentation can never disrupt the SSE path.
151144
"""
152-
global _active_stream_count
153145
try:
154146
_ensure_instruments()
155147

@@ -164,9 +156,8 @@ def record_stream_closed(outcome: StreamOutcome, duration_seconds: float) -> Non
164156
statsd.increment("agentex.task_stream.closed", tags=[f"outcome:{outcome}"])
165157
# Datadog histograms conventionally take milliseconds for durations.
166158
statsd.histogram("agentex.task_stream.duration", duration_seconds * 1000)
167-
# Report the concurrency level as an absolute gauge, not a delta.
168-
_active_stream_count -= 1
169-
statsd.gauge("agentex.task_stream.active", _active_stream_count)
159+
# No StatsD "active" gauge — concurrency is OTel-only; a per-worker
160+
# DogStatsD gauge would flap rather than sum (see record_stream_opened).
170161
except Exception:
171162
logger.debug("Failed to emit agentex.task_stream.closed metric", exc_info=True)
172163

agentex/tests/unit/utils/test_stream_metrics.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ def test_record_functions_swallow_emission_errors():
4747
):
4848
mock_statsd.increment.side_effect = OSError("socket in a bad state")
4949
mock_statsd.histogram.side_effect = OSError("socket in a bad state")
50-
mock_statsd.gauge.side_effect = OSError("socket in a bad state")
5150

5251
# None of these should raise despite the backend blowing up.
5352
stream_metrics.record_stream_opened()
@@ -62,15 +61,14 @@ def test_record_stream_opened_emits_statsd_when_enabled():
6261
patch.object(stream_metrics, "_instruments_initialized", True),
6362
patch.object(stream_metrics, "_opened_counter", None),
6463
patch.object(stream_metrics, "_active_updown", None),
65-
patch.object(stream_metrics, "_active_stream_count", 0),
6664
patch.object(stream_metrics, "statsd") as mock_statsd,
6765
):
6866
stream_metrics.record_stream_opened()
6967

70-
# Opening bumps the opened counter and reports the active concurrency level
71-
# as an absolute gauge (DogStatsD gauges are last-value-wins, not deltas).
68+
# Opening bumps the opened counter. Concurrency ("active") is deliberately
69+
# OTel-only, so the StatsD path emits no gauge (see module rationale).
7270
mock_statsd.increment.assert_called_once_with("agentex.task_stream.opened")
73-
mock_statsd.gauge.assert_called_once_with("agentex.task_stream.active", 1)
71+
mock_statsd.gauge.assert_not_called()
7472

7573

7674
@pytest.mark.unit
@@ -81,7 +79,6 @@ def test_record_stream_closed_emits_statsd_when_enabled():
8179
patch.object(stream_metrics, "_closed_counter", None),
8280
patch.object(stream_metrics, "_duration_histogram", None),
8381
patch.object(stream_metrics, "_active_updown", None),
84-
patch.object(stream_metrics, "_active_stream_count", 1),
8582
patch.object(stream_metrics, "statsd") as mock_statsd,
8683
):
8784
stream_metrics.record_stream_closed("client_disconnect", 3.25)
@@ -94,8 +91,8 @@ def test_record_stream_closed_emits_statsd_when_enabled():
9491
mock_statsd.histogram.assert_called_once_with(
9592
"agentex.task_stream.duration", 3250.0
9693
)
97-
# Closing lowers the active gauge to the new absolute level (1 -> 0).
98-
mock_statsd.gauge.assert_called_once_with("agentex.task_stream.active", 0)
94+
# Concurrency ("active") is OTel-only, so closing emits no StatsD gauge.
95+
mock_statsd.gauge.assert_not_called()
9996

10097

10198
@pytest.mark.unit

0 commit comments

Comments
 (0)