Skip to content

🧹 fix: Await Job Cleanup and Measure Retained Resources - #249

Merged
danny-avila merged 2 commits into
mainfrom
lia/runner-cleanup-memory
Sep 25, 2026
Merged

danny-avila merged 2 commits into
mainfrom
lia/runner-cleanup-memory

Conversation

@lia-by-librechat

@lia-by-librechat lia-by-librechat Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Add post-cleanup resource measurements so runner memory growth can be distinguished from active work, intentionally persistent sessions, and failed disposable cleanup. Also fix /execute acknowledging completion before its asynchronous cleanup has settled.

This is an investigation/observability change, not a claim that the reported production retention is reproduced or resolved. No resource requests, HPA settings, mount sizes, namespace permissions, or process-termination behavior change.

Behavior

Previously:

execute -> pre-cleanup memory log -> upload -> HTTP response -> cleanup

Now:

execute -> existing diagnostic -> upload -> cleanup -> resource sample -> HTTP response
  • Sample cgroup v2 memory.current, anon, file, and shmem at the visible cgroup mount root, covering the API and sibling jail cgroups where available.
  • Sample /tmp allocated bytes/inodes with statfs, identify whether it is tmpfs, and count disposable/session/other workspace-root entries without traversing untrusted trees.
  • Export fixed-label Prometheus metrics, a sample timestamp, availability indicators, and structured logs. Unreadable sources remove stale gauge values rather than reporting zero.
  • Preserve session files and pinned UIDs. Preserve quarantine/retry behavior for failed disposable removal. Record those outcomes separately.
  • Await cleanup before success, priming-error, execution-error, and validation-error responses. Upload still precedes cleanup; client disconnect still does not release a running job's workspace.
  • Add a CI step repeating file-heavy workspace cleanup on a real 1 GiB tmpfs. Add a separately gated real-NsJail test for normal completion, timeout, output overflow, and detached children holding unlinked files.

file includes shmem. The runner's /tmp ceiling does not bound all container memory, including distinct jail tmpfs mounts. Samples are runner-wide last-cleanup observations, not per-job attribution or continuously refreshed gauges. The README documents scope, unavailable sources, concurrency, intentional retention, and test setup.

Verification

Check Result
Focused Bun tests in isolated Linux container 250 passed across 20 files
New metrics/cleanup/route tests separately 11 passed
Real tmpfs stress, 24 cycles with an 8 MiB payload and 64 small files Passed; each cycle restored bytes/inodes near baseline and released its UID
Response-ordering regression against original route Four failures reproduced; all pass with the patch
API bun run build Passed
API npx --no-install tsc --noEmit Fails with the same eight baseline diagnostics, no added diagnostics
Prettier on the five new TS files Passed using the repository's pinned Prettier with API's two-space indentation
Workflow YAML syntax and git diff --check Passed

Existing typecheck diagnostics are in api/hosted-app.routes.test.ts, api/session-inputs.routes.test.ts, hosted-app.ts, job-cleanup.test.ts (three), tool-call-socket-proxy-runtime.test.ts, and workspace-isolation.test.ts, all under api/src. They were measured before editing and left out of scope.

The focused set covers cleanup, isolation/reaper, sessions/checkpoints, input priming/downloads, artifact walking, execution capability checks, route validation/binding/timeouts/disconnects, NsJail wrapper/setup-gate fixtures, workspace commands, and lifecycle hooks. The worker's fixed /tmp is read-only, so Linux subprocess fixtures ran in a disposable container using its own writable fixture directory; no host permissions were changed.

Not run: the opt-in real-NsJail descendant test (requires an appropriately configured isolated runner image), production soak/telemetry comparison, full local test suites, and live HPA validation. Passing filesystem cleanup and wrapper fixtures does not prove production namespace teardown.

Subsystem review

Reviewed writers/readers and ordering through prime, execute, upload, cleanup, quarantine, retained-UID retry, session persistence, and client disconnect. Authorization and user-visible response schemas are unchanged. Metrics do not follow workspace symlinks or use user-controlled paths/labels. No persistent-state migration or service-side coordination is required. Reaper-only changes appear on the next job cleanup sample.

Code graph and source investigation used main at 67d75d859aee891923c40cde1db073489d74a424. SQL import reachability was a floor; full codegraph service closure was not computed.

Codex follow-up: Helm scrape discovery

Head 8303f6569b6f89ae59b3f318f4356fc6ebc6e3b2 fixes the valid P2 finding that the new API collectors were not discovered by chart-managed PodMonitors.

  • Added a runner-specific PodMonitor on /metrics, named port sandbox, using the runner pod selectors. Preserved the worker's health scrape and shared timing overrides.
  • Added opt-in metrics.sandboxRunner.ingressFrom peers because default runner NetworkPolicy blocks Prometheus. Empty defaults preserve worker-only ingress; namespace and pod selectors must target trusted scrapers. The runner port also serves execution requests. Sandbox egress and manifest verification are unchanged.
  • Bumped chart version to 0.3.2 as required by Chart.yaml. No deployment or publication was performed.
  • Added tests/sandbox_runner_metrics.sh to Deployment Config Tests. Real Helm renders check monitor/port/selector alignment, timing overrides, disabled components, missing older values, unchanged default access, configured peer restrictions, and unchanged sandbox egress. This regression fails on the reviewed template and passes on the fix.

Review-round checks: Helm render regression and Helm lint passed; block_root_package_delivery.sh, sandbox_runner_healthcheck.sh, bridge_pairing_rollout.sh, and release-versioning.sh passed; ShellCheck, bash syntax, YAML syntax and diff whitespace checks passed. The cleanup metrics/job/route tests passed (11 tests). API npx --no-install tsc --noEmit still reports exactly the eight baseline diagnostics listed above, with no new diagnostics. No TypeScript production code changed in this round.

Subsystem review followed metrics registration, /metrics routing, deployment pod labels and ports, both monitor selectors, network ingress/egress, default/disabled settings, and older-values compatibility. Live cluster scraping, production soak, real-NsJail descendant verification, and full local suites remain unrun. The old head's CI was green; the new head has its own CI run and needs a fresh external review.

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Ready for maintainer-triggered review of exact head e3bb21fc1a8d2377b22ccc8dbad6dd1d4d3fc509.

This head adds post-cleanup resource telemetry, waits for cleanup before /execute responses, preserves session/quarantine/UID retry semantics, and adds regression coverage plus a CI tmpfs stress step.

Please focus on cleanup/response ordering, concurrent cleanup samples, session preservation, UID retention on failed removal, and cgroup/tmpfs metric scope. Subsystem self-review is complete. Focused Linux tests passed; the API typecheck still has only its eight pre-existing diagnostics.

The real-NsJail detached-descendant test and production soak remain unrun. This head does not claim to fix the production retention mechanism or verify every descendant termination path. A maintainer must request the external review; Lia cannot trigger it through the GitHub App.

@danny-avila

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-25T03:02:15.246481Z 8303f65 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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

Here are some automated review suggestions for this pull request.

Reviewed commit: e3bb21fc1a

ℹ️ 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".

type MemoryKind = typeof memoryKinds[number];
type WorkspaceKind = typeof workspaceKinds[number];

export const postCleanupMemory = new Gauge({

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 Scrape the sandbox-runner metrics endpoint

In Helm deployments that rely on the chart-managed metrics.enabled PodMonitor, these new metrics are never collected. The worker-sandbox monitor in helm/codeapi/templates/podmonitor.yaml selects the service-worker pod and its health port, while these collectors are registered in the separate sandbox API process exposed through the sandbox-runner's sandbox port. Add a sandbox-runner scrape endpoint to the PodMonitor; otherwise the retention metrics added here are unavailable outside structured logs.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 8303f6569b6f89ae59b3f318f4356fc6ebc6e3b2.

Added a separate sandbox-runner PodMonitor selecting the runner pod labels and /metrics on the named sandbox port. It inherits the configured scrape interval/timeout and preserves the existing service-worker health scrape.

Following the scrape path also exposed a NetworkPolicy blocker. Added explicit, opt-in metrics.sandboxRunner.ingressFrom peers and documented matching the Prometheus namespace AND pod labels. The default empty list preserves worker-only ingress, because this same TCP port also exposes /execute. No egress rules or manifest verification were relaxed.

tests/sandbox_runner_metrics.sh reproduces the missing runner endpoint on the reviewed template and passes after the fix. Coverage includes labels/ports, timing overrides, disabled components, old/missing values, unchanged default policy, and scoped scrape ingress with unchanged egress. Wired into Deployment Config Tests. Helm lint and ShellCheck pass; cleanup/route tests also pass. Live Prometheus scraping was not tested.

@lia-by-librechat

Copy link
Copy Markdown
Contributor Author

Ready for maintainer-triggered review of exact head 8303f6569b6f89ae59b3f318f4356fc6ebc6e3b2.

This head addresses Codex's P2 scrape-discovery finding with a sandbox-runner PodMonitor, explicit opt-in NetworkPolicy scrape peers, chart documentation/version bump, and a CI Helm-render regression. Default sandbox access, execution-manifest verification, egress, and the previous cleanup implementation are unchanged. Replied to the inline finding with the fixing commit.

Please review end-to-end scrape discovery and ingress restrictions, including older-values compatibility and disabled configurations. Subsystem invariant self-review and focused checks passed; API typechecking still has only its eight pre-existing diagnostics. CI for this head has started. Live Prometheus scraping, production soak, and the real-NsJail descendant test remain unrun.

The prior Codex review covers only e3bb21fc1a8d2377b22ccc8dbad6dd1d4d3fc509, not this new head. A maintainer must request the fresh external review; Lia cannot trigger it through the GitHub App.

@danny-avila

Copy link
Copy Markdown
Collaborator

@codex review the latest head

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 8303f6569b

ℹ️ 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".

@danny-avila
danny-avila merged commit cf0e668 into main Sep 25, 2026
10 checks passed
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.

2 participants