mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
Merge pull request #554 from ashishpatel26/fix/481-dashboard-hero-tile-multi-worker-savings
fix(dashboard): stable 'Proxy $ Saved' hero tile under --workers > 1 (#481)
This commit is contained in:
commit
fd73b88368
3 changed files with 45 additions and 8 deletions
|
|
@ -105,12 +105,12 @@
|
|||
<div class="bg-surface rounded-lg p-4 border border-border">
|
||||
<div class="text-xs text-gray-500 uppercase tracking-wide mb-1">Proxy $ Saved</div>
|
||||
<div class="flex items-baseline gap-2">
|
||||
<span class="text-3xl font-light tabular-nums text-emerald-400" x-text="'$' + formatCurrency(stats.cost?.savings_usd || 0)"></span>
|
||||
<span class="text-3xl font-light tabular-nums text-emerald-400" x-text="'$' + formatCurrency(stats.persistent_savings?.lifetime?.compression_savings_usd || 0)"></span>
|
||||
</div>
|
||||
<div class="mt-2 text-xs text-gray-500">
|
||||
<span x-show="stats.cost?.savings_usd > 0"
|
||||
<span x-show="(stats.persistent_savings?.lifetime?.compression_savings_usd || 0) > 0"
|
||||
x-text="formatNumber(stats.tokens?.proxy_compression_saved || 0) + ' proxy tokens only; ' + cliFilteringLabel + ' excluded from $'"></span>
|
||||
<span x-show="!(stats.cost?.savings_usd > 0)"
|
||||
<span x-show="!((stats.persistent_savings?.lifetime?.compression_savings_usd || 0) > 0)"
|
||||
x-text="formatNumber(stats.requests?.total || 0) + ' requests processed'"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3099,12 +3099,13 @@ def run_server(
|
|||
# sticky-session workaround.
|
||||
logger.warning(
|
||||
"Headroom is running with workers=%d. The in-memory CCR store, "
|
||||
"compression cache, prefix tracker, and TOIN state are all "
|
||||
"compression cache, prefix tracker, TOIN state, and CostTracker are all "
|
||||
"per-process; multi-worker deployments produce silent retrieval "
|
||||
"failures and avoidable cache busts when sessions land on different "
|
||||
"workers. Run --workers 1 (or place a sticky-session load balancer "
|
||||
"in front of multiple --workers 1 processes). See RUST_DEV.md → "
|
||||
"'Multi-worker deployment — CCR fragmentation'.",
|
||||
"failures, avoidable cache busts, and an unstable dashboard 'Proxy $ Saved' "
|
||||
"hero tile (each /stats poll hits a different worker's partial total) when "
|
||||
"sessions land on different workers. Run --workers 1 (or place a "
|
||||
"sticky-session load balancer in front of multiple --workers 1 processes). "
|
||||
"See RUST_DEV.md → 'Multi-worker deployment — CCR fragmentation'.",
|
||||
workers,
|
||||
)
|
||||
os.environ[_MULTI_WORKER_CONFIG_ENV] = json.dumps(_proxy_config_payload(config))
|
||||
|
|
|
|||
|
|
@ -211,6 +211,42 @@ def test_record_compression_savings_skips_empty_updates_and_normalizes_timestamp
|
|||
assert persisted["history"][-1]["timestamp"] == "2026-03-27T12:34:00Z"
|
||||
|
||||
|
||||
def test_savings_tracker_save_does_not_flock_target_inode_before_replace(tmp_path, monkeypatch):
|
||||
path = tmp_path / "proxy_savings.json"
|
||||
tracker = SavingsTracker(path=str(path))
|
||||
|
||||
tracker.record_request(
|
||||
model="gpt-4o",
|
||||
input_tokens=120,
|
||||
tokens_saved=10,
|
||||
timestamp="2026-03-27T09:00:00Z",
|
||||
)
|
||||
assert path.exists()
|
||||
|
||||
flock_calls: list[int] = []
|
||||
|
||||
class _FcntlSpy:
|
||||
LOCK_EX = 1
|
||||
LOCK_UN = 2
|
||||
|
||||
def flock(self, _fh, operation: int) -> None:
|
||||
flock_calls.append(operation)
|
||||
|
||||
monkeypatch.setattr(savings_tracker_module, "_HAS_FCNTL", True, raising=False)
|
||||
monkeypatch.setattr(savings_tracker_module, "_fcntl", _FcntlSpy(), raising=False)
|
||||
|
||||
tracker.record_request(
|
||||
model="gpt-4o",
|
||||
input_tokens=80,
|
||||
tokens_saved=5,
|
||||
timestamp="2026-03-27T09:10:00Z",
|
||||
)
|
||||
|
||||
assert flock_calls == []
|
||||
persisted = json.loads(path.read_text(encoding="utf-8"))
|
||||
assert persisted["lifetime"]["tokens_saved"] == 15
|
||||
|
||||
|
||||
def test_litellm_resolution_and_savings_estimation_fallbacks(monkeypatch):
|
||||
def fake_cost_per_token(*, model, prompt_tokens, completion_tokens):
|
||||
if model in {"gpt-4o", "anthropic/claude-sonnet-4-6"}:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue