Skip to content

fix(compute): size the gateway for its first turn and test it without swap - #3822

Merged
freeqaz merged 2 commits into
mainfrom
memory-2700
Oct 27, 2026
Merged

freeqaz merged 2 commits into
mainfrom
memory-2700

Conversation

@freeqaz

@freeqaz freeqaz commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Finding 2700. Since the OpenClaw pin update in #2982, an embedded Gateway needs much more memory on its first chat turn:

Stub-model turn, 1 CPU, no swap Old pin (aaf04ff) Current main (34d3848)
cgroup memory at ready 0.91-0.99 GiB 1.56-1.61 GiB
peak (memory.peak), first turn 1.74-1.89 GiB 2.53-2.69 GiB (2.69-2.78 GiB in runtime-image-gateway-unclean-restart, whose turn client runs in the container)
after 5 turns, settled 1.6-1.8 GiB 2.3-2.4 GiB
--memory 2g --memory-swap 2g passes OOM-killed on the first turn
--memory 3g --memory-swap 3g - passes, peak 2.69 GiB (about 10% headroom)

Turns 2-5 add nothing, and with no turn the Gateway stays at about 1.7 GiB, so this is a one-time cost of the first turn, not a per-turn leak. The growth is in the V8 heaps of OpenClaw's worker_threads isolates (about 25 on the new pin, about 18 on the old one); the main thread's heap stays at 0.3-0.5 GiB.

The runtime image probe tests capped the Gateway at --memory 2g. Docker pairs that with as much again in swap, and CI runners swap, so the tests passed while the Gateway swapped 0.25-1 GiB. On a host without swap the same tests OOM-killed the Gateway ("fetch failed: other side closed"). Kubernetes nodes usually run without swap, and the production example's 3Gi Gateway limit leaves about 10% headroom over a stub turn.

Change

  • Tests: the image probe helpers share one Gateway memory setting in tests/helpers/runtime-image-startup.mjs: --memory 4g --memory-swap 4g, the production limit with no swap, so swap can no longer hide growth. The unused per-call memory option is gone.
  • Sizing: Gateway requests.memory 1792Mi -> 2560Mi and limits.memory 3Gi -> 4Gi in the production example, the profile renderer, the local Kubernetes stack (internal/occdev), their tests, and the sizing docs. Requests still cover use between turns (now 2.3-2.4 GiB); the limit leaves about 30% headroom over the first-turn peak.
  • Notice: a 2026-10-27 breaking-change entry for Installations with a lower Gateway limit.

Verification

  • Measurements above: a stub-model probe on the real runtime images of both pins on a remote test VM, sampling the container cgroup every second and process.memoryUsage() of every isolate every 500 ms (scratch probe, not committed).
  • runtime-image-gateway-unclean-restart and the rest of Image Runtime Startup 2 on a remote test VM: see the comment below.
  • profile-renderer.test.mjs 67/67; the kubernetes-compute conformance case for the production example; go test ./internal/occdev -run TestDevelopmentInstallationSizesAgentsFromMeasuredUse.
  • eslint and prettier on the touched files.

Risks

  • Larger requests mean fewer Agents per node: plan 2560Mi per embedded Agent and 3328Mi per dedicated Codex Agent. Existing Installations keep their values until an operator changes them (see the notice).
  • The tests now pass at the production limit, so growth below 4g no longer fails them; the first-turn peak needs a deliberate check when the OpenClaw pin moves.
  • The dedicated Codex Gateway was not measured on the new pin; it shares the setting.

… swap

Since the OpenClaw pin of #2982 an embedded Gateway is ready at 1.5-1.6 GiB
and peaks at 2.6-2.8 GiB on its first turn, when OpenClaw starts most of its
worker threads (finding 2700). The runtime image probe tests capped it at
--memory 2g, which Docker pairs with as much swap again; CI runners swap,
so the tests passed while a swapless host OOM-killed the Gateway.

- Image probe tests share one Gateway memory setting, --memory and
  --memory-swap both 4g, so swap can no longer hide growth.
- Gateway sizing in the production example, the profile renderer and the
  local Kubernetes stack: requests 2560Mi (was 1792Mi), limits 4Gi (was
  3Gi). The 3Gi limit left about 10% headroom over a stub turn.
- Breaking-change notice for Installations with a lower Gateway limit.
@freeqaz
freeqaz requested a review from a team as a code owner October 27, 2026 05:51
@clawsweeper

clawsweeper Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@freeqaz

freeqaz commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator Author

Free's clanker here. Image Runtime Startup 2 on a remote test VM at bd4b4fe, with the Gateway at --memory 4g --memory-swap 4g: all 6 files passed, including runtime-image-gateway-unclean-restart.test.mjs (3 tests that OOM-killed the Gateway at 2g without swap). profile-renderer.test.mjs passed 67/67 and the production-example conformance case passed there too. f4c24f3 only corrects the peak range in two comments/docs (2.5-2.8 GiB).

@clawsweeper clawsweeper Bot added clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-repro Preliminary submission classification; full source review pending. P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-repro Preliminary submission classification; full source review pending. labels Oct 27, 2026
@clawsweeper

clawsweeper Bot commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Codex review: blocked before merge.

What this changes

This PR raises Gateway memory requests to 2560Mi and limits to 4Gi, and runs runtime probes without swap.

Example: An embedded Gateway answers its first chat turn on a host without swap.

  • Before: The 2 GiB runtime-test container is reported OOM-killed; generated Kubernetes configurations allow 3Gi.
  • After: Runtime tests use 4 GiB with swap disabled, and generated Kubernetes configurations request 2560Mi with a 4Gi limit.

Review scores

Measure Result What it means
Overall readiness 🦐 gold shrimp (3/6) A focused, useful patch with credible runtime measurements and passing selected CI, held below a full pass by incomplete installation-upgrade evidence.
Proof confidence 🦐 gold shrimp (3/6) Real behavior proof is not required for maintainer- or bot-authored pull requests.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Product

Kind: Bug fix · Worth it: Yes · Fix scope: Complete
User problem: A Gateway can lose its first chat connection when its container exhausts memory, while swap-enabled tests conceal the pressure.
Reason: Measured use supports the additional budget, and the collaborator author explicitly owns the sizing direction and capacity tradeoffs.

Merge readiness

⛔ Blocked before merge - 1 item remains

Keep this PR open: it addresses measured Gateway memory growth through the existing sizing owners, and no definite introduced code defect was found.

Priority: P2
Reviewed head: f4c24f34459dd71bbc97364792d39721bfee7643

Before merge

  • Add data-model compatibility proof - The review found that existing stored data may not work after upgrade. Show that existing data still loads and works with this change.

Findings

None.

Tests

  • Missing end-to-end proof: Supply a fresh-install and existing-Installation upgrade run showing the selected budgets, retained settings and Agent state, and a successful first chat after redeployment.
Agent review details

How this fits together

Installation generation supplies resource budgets to Kubernetes Compute, which applies them to Agent workloads; runtime-image tests exercise the production wrappers against a stand-in model provider.

flowchart LR
  A[Installation profile or development setup] --> B[Gateway resource configuration]
  B --> C[Kubernetes Compute]
  C --> D[Agent Gateway Pod]
  E[Runtime image probes] --> F[Container with swap disabled]
  F --> G[Production Gateway wrapper]
Loading

Technical review

Best possible solution:

Land the focused sizing and swap-control change after verifying the documented update of an existing Installation.

Do we have a high-confidence way to reproduce the issue?

The author supplies a concrete swapless first-turn OOM scenario and comparative cgroup measurements, corroborated by the earlier diagnostic discussion; this review did not execute the runtime.

Is this the best way to solve the issue?

Updating the existing sizing owners and disabling swap in their runtime probes is proportionate to the measured footprint; this provides headroom rather than repairing OpenClaw's underlying memory growth.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against 9d9e8dd27b7b.

Provenance checked

Testing

Proof path: in-process harness.

Security

None.

Evidence

What I checked:

Labels

Label changes:

  • add P2: Measured first-turn memory growth warrants a focused runtime-sizing repair, without evidence of a widespread production outage.
  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.

Label justifications:

  • P2: Measured first-turn memory growth warrants a focused runtime-sizing repair, without evidence of a widespread production outage.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Demonstrate fresh installation and upgrade of an existing Installation, preserving settings and Agent state through a successful first chat.

Rating scale

6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

Reviewed October 27, 2026, 2:08 AM ET / 06:08 UTC.

@freeqaz freeqaz left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Free's clanker here (an AI agent working on Free's behalf). Independent review of head f4c24f3.

Verdict: no blocking issues. The sizing is consistent, the numbers follow from the measurements, and the stricter test setting catches the regression it targets.

Sizing consistency. I searched the repository for 1792Mi, 3Gi, 1.75 GiB, 2.2 GiB, 3 GiB, 2560Mi, 3328Mi, 3.25 GiB and 2.5 GiB. Every Gateway statement now reads 2560Mi/4Gi: the production example (deploy/examples/production/installation.yaml:75,78), the renderer (scripts/render-installation-profile.mjs:1858), occdev (internal/occdev/kubernetes.go:381), the reference, the guides, the Compose flow, and the conformance, renderer and Go tests. No old value is left. The Harness (768Mi/6Gi), container defaults and Helm values are unchanged. The Helm chart has no Gateway default. The dedicated Codex total adds up: 2560 + 768 = 3328 Mi = 3.25 GiB.

Measurements. The request is 2.5 GiB against 2.29-2.38 GiB settled between turns, so it still covers what an Agent holds. The limit is 4 GiB against a 2.53-2.78 GiB first-turn peak (no swap), about 1.2 GiB of headroom. 3Gi would leave about 10%.

Breaking-change notice. It follows the file's format (What breaks / Who is affected / How to tell / Steps, marked untested), is dated 2026-10-27 and is placed newest first. Suite Audit and Static Checks are green on this head, so the word limits hold.

Test helper. Both probe launchers spread the shared gatewayMemoryArguments, which set --memory 4g --memory-swap 4g: runEmbeddedGatewayProbe (tests/helpers/runtime-image-model-probe.mjs:237) and runStartupProbeScenario (tests/helpers/runtime-image-startup-probe.mjs:402). No caller still passes memory. productionGatewayMemoryLimit and startupProbeMemoryLimit are gone and nothing imports them. The other runtime-image tests start containers without a memory limit, as before.

Mutant. I set the shared limit back to 2g, so --memory 2g --memory-swap 2g, and ran Image Runtime Startup 2 on a remote test VM that has swap like CI. It failed: all three embedded-Gateway cases in runtime-image-gateway-unclean-restart.test.mjs hit fetch failed / SocketError: other side closed after about 18-20 s. That is finding 2692's OOM signature. The other files passed. The no-swap flag is what makes the test catch this.

CI cost. Image Runtime Startup 1/2/3 took 542/452/420 s on this head. The last six main runs took 343-541 / 463-514 / 405-609 s, so there is no slowdown. Image Runtime Startup 2 runs up to 4 files with 2 tests each. Gateways that used to swap past 2 GiB now stay resident at up to about 2.8 GiB each, which is roughly 22 GiB in the worst case. That is fine on the 32-vCPU runner, and the lane is green.

Nits (non-blocking):

  1. docs/guides/deploy/installation-profiles.md:47: the row covers "embedded or dedicated", but only the embedded Gateway was re-measured. The dedicated Gateway's old measurements (1.2-1.6 GiB) were dropped. Either say the dedicated Gateway was not re-measured, or measure it, because a dedicated Codex Agent now reserves 768 Mi more on that basis.
  2. tests/integration/runtime-image-model-probe.test.mjs: the CPU-contention case runs eight node hogs inside the Gateway container. That uses about 0.4 GiB of the 4 GiB, so the margin over the peak is smaller there. It passed on the head (Image Runtime Startup 3), so this is something to watch rather than change.
  3. Pre-existing, for a follow-up: tests/helpers/harness-topology-k3d-real.mjs:915 still limits the real dedicated Gateway to 2Gi, while the profiles page says a dedicated Gateway serving native admin chat was OOM-killed at 2Gi. The k3d lanes are green on this head.

@freeqaz
freeqaz merged commit 7379613 into main Oct 27, 2026
67 of 69 checks passed
@freeqaz
freeqaz deleted the memory-2700 branch October 27, 2026 06:23
freeqaz added a commit that referenced this pull request Oct 27, 2026
…limit (#3835)

Drops the QA helper's redundant 4Gi Gateway override (the dev-up launcher has written 4Gi since #3822) and derives the runtime-image startup memory cap from the shared productionGatewayMemoryLimitGi constant.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant