mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
2 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
517bf992cf
|
fix(proxy): quarantine compression while timed-out workers run (#2292)
## Description
A request-side `asyncio.wait_for()` timeout stops waiting, but it cannot
preempt an executor thread that already started. The proxy counted those
late workers and still admitted more compression, so repeated slow calls
could consume the whole compression pool and charge every request
another full timeout.
This change tracks running post-timeout workers as timeout debt and
quarantines request-path compression while that debt is non-zero. New
attempts raise `CompressionQuarantinedError` before executor admission,
using an `asyncio.TimeoutError` subclass so Python 3.10 handlers apply
the existing compression-failure policy. Quarantine clears automatically
after all known timed-out workers genuinely exit.
Mitigates #946 and #810. It does not attempt to kill the first running
thread; Python cannot safely preempt it.
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [x] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)
## Changes Made
- Track started, finished, timed-out, and debt-recorded state under the
existing compression metrics lock.
- Reject new compression before enqueue while timed-out workers remain;
clear quarantine on the final worker exit.
- Preserve queued-timeout behavior: work cancelled before worker start
does not activate quarantine; a cancellation/start race is
conservatively tracked as running debt.
- Add `/health` and `/stats` runtime fields for quarantine state, worker
debt, activations, and skips.
- Add `headroom_compression_quarantine_total{event="activated|skipped"}`
Prometheus counters.
- Add regression, recovery, queue-race, runtime-payload, export, reset,
and Python 3.10 exception-class coverage.
- Update `CHANGELOG.md`; no dependency or lockfile changes.
## Reproduction
On base commit `
|
||
|
|
d7283387ac
|
feat(metrics): export compression-failed and kompress size-gate counters (#1569)
## What
Two Prometheus counters that make previously-invisible compression
behavior measurable on `/metrics`.
- `headroom_compression_failed_total{reason=timeout|error}` —
incremented at both Anthropic fail-open sites (single-message and
batch-create), where an optimization exception forwards the request
uncompressed. Before this, ratio could bleed at these sites with nothing
in `/metrics`; only a response header recorded the single-message case.
The timeout/error split separates "compression budget too tight" from
"real bug".
- `headroom_kompress_size_gate_total{outcome=within|exceeded}` — the
size gate (#1171) routes oversized blocks off ModernBERT. The
within/exceeded split proves whether the gate ever fires on real
traffic. `within` counts a gate pass, not whether ML compression then
ran.
## How
Both reuse the existing `PrometheusMetrics` singleton and the
established `defaultdict(int)` counter + text-exposition pattern. The
handler records via `self.metrics`; `content_router` records through the
existing `CompressionObserver` hook to avoid an import cycle. Cleared in
`reset_runtime`; exposition blocks are emitted only when non-empty.
## Verification
- `tests/test_prometheus_obs_counters.py` (6 tests): per-reason/outcome
bucketing, empty-string default buckets, exposition format, conditional
absence until recorded, and reset clearing. All green.
- Counter increments and well-formed exposition (HELP/TYPE balanced,
labels escaped) confirmed by direct exercise; gate `within`/`exceeded`
shown mutually exclusive across the eligible-block call sites.
Single commit, rebased on current `main`.
Addresses #1567.
|