feat(scheduler): concurrency cap on by default + fail-open fix (v0.143.0)#244
Merged
Conversation
…3.0) Phase 1 of docs/concurrency-cap-plan.md. Every live session holds a claude process (hundreds of MB); an unbounded burst of scheduled work can OOM the box. - The scheduler cap now defaults to a RAM-derived value (max(3, floor(GB/1.5))) instead of 0/unlimited. Resolved live as env → operator Settings → derived by the new single-source-of-truth Automations.concurrencyCap() (the static `maxConcurrent` field is gone), so a Settings change lands next tick, no restart. - Fix the fail-open: aliveSessionCount() fell back to 0 when tmux liveness was unpollable (always on the Linux LauncherSessionBackend), silently disabling the cap under the exact load it's for. It now uses a DB count of running rows (new runningSessionCount()); the crash sweep keeps that set honest. - Settings.maxConcurrentSessions get/set (null=unset→derived, 0=unlimited, N=cap) + GET/PUT /api/settings/concurrency (owner/admin, audited) + a Settings → Runtime defaults → "Concurrency cap" panel (live count + effective cap + source; env-pinned installs are read-only). - scripts/concurrency-cap-test.cjs: 20 assertions (derived math, Settings semantics, resolver order, DB fallback). typecheck + web build + 68/68 governance all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 1 of
docs/concurrency-cap-plan.md— turn the whole-box concurrency cap on, correctly.Why
Every live session holds a
claudeprocess (hundreds of MB). Automations/cron/tasks can burst; an unbounded burst swaps/OOMs the box. The cap already existed but was opt-in and 0 (unlimited) by default, and it fail-opened to 0 whenever tmux liveness couldn't be polled — disabling itself under exactly the load it's for.What changed
derivedConcurrencyCap()=max(3, floor(totalGB / 1.5))(2 GB → 3; 32 GB → ~21). Resolved live as env → operator Settings → derived by the newAutomations.concurrencyCap()(single source of truth; the oldprivate readonly maxConcurrentfield is gone). A Settings change takes effect on the next tick — no restart.TerminalManager.aliveSessionCount()now falls back torunningSessionCount()(a DB count ofrunningrows) whenaliveNames()is null, instead of0. The crash sweep keeps that set honest, so it's a safe proxy.Settings.maxConcurrentSessions()/setMaxConcurrentSessions()(null= unset → derived;0= unlimited;N>0= cap),GET/PUT /api/settings/concurrency(owner/admin, auditedsettings.concurrency.updated), and a Settings → Runtime defaults → "Concurrency cap" panel showing the live running count + effective cap + its source (env / operator / box default). Env-pinned installs render read-only.Scope
Phase 1 only — the cap still governs the scheduler paths (cron /
once/ task). The chat/webhook admission gate + durable queue is Phase 2 (unchanged here). Per-box (cross-tenant) capping stays a documented future.Verification
npm run typecheck✓ ·cd web && npm run build✓ ·npm run test:governance→ 68/68 ✓scripts/concurrency-cap-test.cjs→ 20/20 (derived math, Settings get/set/clear, resolver order incl. env precedence + blank/garbage env, DB fallback).🤖 Generated with Claude Code