Skip to content

Pool Controller v2 - #43

Merged
Harsh-2002 merged 1 commit into
mainfrom
codex/pool-controller-v2
Aug 11, 2026
Merged

Pool Controller v2#43
Harsh-2002 merged 1 commit into
mainfrom
codex/pool-controller-v2

Conversation

@Harsh-2002

Copy link
Copy Markdown
Owner

Summary

  • replace target-concurrency tuning with stable, burst, and immediate-pressure capacity signals at a 70% utilization target
  • coordinate global memory/CPU admission fairly across functions, with bounded concurrent spawns, borrowed-idle reclamation, and safe scale-down hysteresis
  • migrate pool_config without data loss, normalize scale-to-zero policy, and publish the new REST/MCP/Prometheus/UI metrics
  • update operator docs with measured before/after capacity results and refresh embedded docs/UI assets

Validation

  • make test
  • make lint
  • cd frontend && npm test && npm run lint && npm run build
  • GOCACHE=/tmp/orva-go-cache make build-all
  • go test -race ./backend/internal/pool
  • shellcheck test/atscale.sh test/errors-test.sh
  • isolated nsjail error-contract E2E: 9/9
  • isolated concurrency-32 sandbox smoke: 1,000/1,000 HTTP 200, zero rejections/timeouts, 32-worker effective ceiling
  • docs/reference.md and all MCP/frontend/CLI embedded copies byte-identical

Capacity measurement

Measured throughput changed from 1,144.24 req/s to 1,063.80 req/s (-7.03%, within the 10% gate), cold starts fell from 0.402% to 0.200%, and measured worker churn fell from 69 spawned/37 killed to 32 spawned/0 killed.

Entire-Checkpoint: 01KZRD0B5347GGSYG1V60P1EZZ
@Harsh-2002
Harsh-2002 merged commit f7bbe9a into main Aug 11, 2026
22 checks passed
@Harsh-2002
Harsh-2002 deleted the codex/pool-controller-v2 branch August 11, 2026 12:41

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

p.Pool.RecordLatency(acq, time.Since(dispatchStart))

P2 Badge Measure streaming service time after consuming all frames

For a streaming handler, DispatchEx returns as soon as it reads response_start; the later NextFrame loop holds the worker for the actual stream lifetime. Recording latency here therefore measures TTFB rather than service time—a 30-second stream may be sampled as a few milliseconds—so the Little's-Law stable and burst signals under-predict the warm capacity required by streaming workloads. Record the sample after the frame loop terminates, immediately before release.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

s.spawnWG.Add(1)
go func() {
defer s.spawnWG.Done()
defer func() { <-p.spawnSlots }()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Wake the scaler after each spawn slot is freed

With a burst that needs more than four new workers, all request nudges can be consumed while spawnSlots is full; when these four spawns finish, this defer releases the slots without waking the controller again. The remaining queued requests therefore wait for the next 2-second tick before another batch of four can start, so a 100-request cold burst can require roughly 48 seconds of ramp-up and exceed the default 30-second request timeout. Nudge the scaler when a slot becomes available while demand remains.

Useful? React with 👍 / 👎.

if t.cgroupConstrained {
physical -= total - budget
}
physical -= reserved

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid subtracting live worker reservations twice

Once workers are running, both MemAvailable and cgroup memory.current already reflect their resident memory, while reserved continues to include every live worker until it is killed. Subtracting the full reservation again here makes the physical gate count live workers twice; for workers using their reservation, admission can stop near 40% of host RAM rather than the documented 80%, producing false memory_capacity limits and capacity timeouts. Only not-yet-visible spawn reservations should be deducted from physical availability; the logical budget can continue using all reservations.

Useful? React with 👍 / 👎.

CASE WHEN scale_to_zero = 1 THEN 0 WHEN min_warm < 1 THEN 1 ELSE min_warm END,
max_warm, idle_ttl_s, max_use_count, scale_to_zero
FROM pool_config`,
`DROP TABLE pool_config`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep the pool migration additive-only

Upgrading any database that still has target_concurrency executes this DROP TABLE pool_config, despite the repository's explicit additive-only migration invariant. The controller can simply leave the now-unused column in place and normalize min_warm with an idempotent UPDATE; rebuilding the table also removes independently added indexes or triggers and makes downgrade compatibility unnecessarily unsafe.

AGENTS.md reference: backend/AGENTS.md:L87-L89

Useful? React with 👍 / 👎.

Comment on lines +101 to +103
if cfg.ScaleToZero && cfg.MinWarm != 0 {
respond.Error(w, http.StatusBadRequest, "VALIDATION", "scale_to_zero=true requires min_warm=0", reqID)
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Replace the now-invalid scale-to-zero example

When an operator follows the shipped example orva pool set --fn greeter --min-warm 2 --max-warm 20 --scale-to-zero from cli/commands/pool.go:33 or docs/CLI.md:580, this new validation returns HTTP 400 because scale-to-zero now requires min_warm=0. Update both examples to use zero, or retain support for the previously documented combination.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant