Skip to content

Commit e16e74f

Browse files
committed
perf(selfhost): document retention/concurrency sizing, fix stale runner docs (#1828)
Prometheus's 180d retention default had no sizing rationale and no comment, unlike the explicitly-justified 336h/14d (Loki) and 168h/7d (Tempo) siblings; git history shows it silently replaced a deliberate 30d default when it became an override-able env var in #1678. Add a comment justifying why metrics can reasonably outlive logs/traces (far cheaper per-day TSDB storage) while lowering the default to 90d, a considered middle ground rather than an unexplained six-month default. QUEUE_CONCURRENCY/QUEUE_BACKGROUND_CONCURRENCY had no core-count-based sizing guidance, unlike PGPOOL_MAX's existing "raise if you see X, watch Y" treatment. Add equivalent guidance anchored to vCPU count. The self-hosting-operations docs claimed the runner service "ships with no CPU/memory limit at all" in two places; this became false once RUNNER_MEM_LIMIT (default 2g) was added for #3893. Fix both occurrences, plus the adjacent table cell making the same now-incorrect claim, to describe the current state: a default memory ceiling with CPU-priority pinning remaining opt-in via docker-compose.override.yml.example.
1 parent b8a1ba4 commit e16e74f

3 files changed

Lines changed: 36 additions & 13 deletions

File tree

.env.example

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,11 +298,21 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review
298298
# # a moderate-load instance (several active repos / a steady
299299
# # contributor-PR stream) on a host with a few spare cores -- review
300300
# # jobs are I/O-bound (GitHub + AI awaits dominate), so raising this
301-
# # mostly buys parallelism, not CPU. Watch gittensory_queue_live_pending
301+
# # mostly buys parallelism, not CPU. As a core-count anchor (#1828):
302+
# # a 2-vCPU host is comfortable around the default of 4; a 4+ vCPU
303+
# # host can reasonably go to 8-12 before the loops' own CPU work
304+
# # (JSON parsing, diff rendering, AI-response handling) starts
305+
# # competing for the cycles the I/O awaits were supposed to free up.
306+
# # Watch gittensory_queue_live_pending
302307
# # / gittensory_queue_oldest_live_pending_age_seconds after raising it;
303308
# # if those stay high, the bottleneck is elsewhere (GitHub rate limit,
304309
# # AI latency, Postgres pool -- see PGPOOL_MAX above), not concurrency.
305310
# QUEUE_BACKGROUND_CONCURRENCY=1 # max low-priority/background jobs allowed to occupy QUEUE_CONCURRENCY slots
311+
# # (default 1 reserves the rest of even a small 2-vCPU host's default
312+
# # 4 slots for live review work). Scale it WITH QUEUE_CONCURRENCY, not
313+
# # independently -- keep it to roughly a quarter to a third of
314+
# # QUEUE_CONCURRENCY (e.g. 2-3 of a 4+ vCPU host's 8-12) so background
315+
# # maintenance can never crowd out every live-review slot.
306316
# CONTRIBUTOR_EVIDENCE_BATCH_SIZE=150 # logins per build-contributor-evidence job; the scheduled run fans out into
307317
# # per-batch jobs above this so the per-login GitHub reads spread across the
308318
# # queue instead of bursting. Set 0 to disable the fan-out (single job).

apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -328,16 +328,20 @@ DISCORD_REPO_WEBHOOKS={"owner/repoA":"https://discord.com/api/webhooks/...","own
328328
+ <code>--profile runners</code>
329329
</td>
330330
<td className="py-2 pr-4 align-top text-muted-foreground">
331-
Unbounded by default — can starve the app under CI load
331+
Unbounded by default — can still starve the app under CI load
332+
</td>
333+
<td className="py-2 pr-4 align-top text-muted-foreground">
334+
Bounded by <code>RUNNER_MEM_LIMIT</code> (default 2g) per replica
332335
</td>
333-
<td className="py-2 pr-4 align-top text-muted-foreground">Unbounded by default</td>
334336
<td className="py-2 align-top text-muted-foreground">
335-
Estimated, and explicitly a known risk, not a guess about typical usage: the{" "}
336-
<code>runner</code> service ships with no CPU/memory limit at all. Production
337-
experience already documented in <code>docker-compose.override.yml.example</code>{" "}
338-
found 3 uncapped runner containers starving the app for CPU on an 8-vCPU box under
339-
real CI load — see that file for the <code>cpu_shares</code>/<code>cpus</code>{" "}
340-
mitigation before co-locating runners with the review stack.
337+
Estimated, and explicitly a known risk on the CPU side, not a guess about typical
338+
usage: the <code>runner</code> service ships with a default memory ceiling (
339+
<code>RUNNER_MEM_LIMIT</code>, default 2g, added by #3893) but no CPU limit.
340+
Production experience already documented in{" "}
341+
<code>docker-compose.override.yml.example</code> found 3 uncapped runner containers
342+
starving the app for CPU on an 8-vCPU box under real CI load — see that file for the{" "}
343+
<code>cpu_shares</code>/<code>cpus</code> mitigation before co-locating runners with
344+
the review stack.
341345
</td>
342346
</tr>
343347
<tr>
@@ -402,10 +406,11 @@ DISCORD_REPO_WEBHOOKS={"owner/repoA":"https://discord.com/api/webhooks/...","own
402406
and still has real headroom), and nothing is so oversized relative to plausible usage that
403407
it should be lowered — including Ollama&apos;s comparatively large 8GiB ceiling, which is
404408
sized for holding one quantized model in memory, not idle overhead. The one real gap is{" "}
405-
<code>--profile runners</code>, which ships with no limit at all; that is a known,
406-
documented tradeoff (see the table above and{" "}
409+
<code>--profile runners</code>&apos;s CPU side: the service has a default memory ceiling (
410+
<code>RUNNER_MEM_LIMIT</code>, default 2g) but ships with no CPU limit at all; that is a
411+
known, documented tradeoff (see the table above and{" "}
407412
<code>docker-compose.override.yml.example</code>) rather than an oversight, since the right
408-
ceiling depends entirely on the host's core count and how many runner replicas you run.
413+
CPU ceiling depends entirely on the host's core count and how many runner replicas you run.
409414
</p>
410415

411416
<h3>Capacity planning: how much disk for N repos at M PRs/month</h3>

docker-compose.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,15 @@ services:
510510
command:
511511
- "--config.file=/etc/prometheus/prometheus.yml"
512512
- "--storage.tsdb.path=/prometheus"
513-
- "--storage.tsdb.retention.time=${PROMETHEUS_RETENTION_TIME:-180d}"
513+
# 90d, not the 336h/14d of Loki or 168h/7d of Tempo below (#1828): that gap is deliberate, not an
514+
# oversight — Prometheus's TSDB compresses numeric samples to ~1-2 bytes each after compaction, so
515+
# metrics cost far less disk per retained day than Loki's raw log lines or Tempo's full span trees,
516+
# and the self-hosting-operations docs' own capacity-planning guidance wants a multi-week/month
517+
# trend window for metrics specifically. That said, 180d (six months) had no sizing rationale of
518+
# its own — it silently replaced a deliberate 30d default when this became an override-able var in
519+
# #1678 — so 90d is the considered number here: a full quarter of history for trend/capacity
520+
# review, without defaulting a small self-host box to open-ended, unbounded-looking retention.
521+
- "--storage.tsdb.retention.time=${PROMETHEUS_RETENTION_TIME:-90d}"
514522
deploy:
515523
resources:
516524
limits:

0 commit comments

Comments
 (0)