Skip to content

The warm pool is created and never claimed from, so a Bot's first action still waits for a cold start #272

Description

@zopeVaibhav

computers.sandbox.warmPool.enabled=true renders a SandboxWarmPool, grants the service account create and delete on sandboxclaims, and holds two pods ready. Nothing ever claims from it. The server has no code path that creates a SandboxClaim, so a Bot's first action still waits for a brand-new Sandbox to schedule and for Chromium to boot — the exact wait the pool exists to remove, now paid for twice.

What the cold start actually does

Every request the sandbox provider makes when a Bot has no computer yet, captured through the provider's own injectable fetchImpl:

provider.warm implemented?  undefined
methods: name, isolation, locate, status, stop, reset, list, sessionOf

GET  /apis/agents.x-k8s.io/v1beta1/namespaces/openbot/sandboxes/bot-knowledge-19lp3wl   404
POST /apis/agents.x-k8s.io/v1beta1/namespaces/openbot/sandboxes
GET  /apis/agents.x-k8s.io/v1beta1/namespaces/openbot/sandboxes/bot-knowledge-19lp3wl

Three calls, none of them a claim. The POST creates a fresh Sandbox from scratch while two warm ones sit idle beside it.

Where the wiring stops

The interface declares the hook, optionally:

server/src/computer/provider.ts:85

/** Prepare provider resources before the first computer request. */
warm?(): Promise<void>;

And the server calls it at server/src/index.ts:206:

if (computerProvider?.warm) {
  void computerProvider.warm();
}

The guard is never true. createComputerProvider returns one of three shapes — docker, shared, sandbox — and typeof provider.warm is undefined for all three. The string sandboxclaim appears nowhere under server/. Because warm?() is optional, TypeScript is content and the if reads as deliberate rather than unfinished.

This is a gap between the chart and the code that consumes it, not a typo. Claiming is what the upstream controller keys on claim.Spec.WarmPoolRef to do; without a claim, a warm pool is only pods.

Reproduction

  1. Render the chart with the pool on and the CRDs declared:

    helm template ob charts/openbot \
      --set computers.mode=sandbox \
      --set computers.sandbox.warmPool.enabled=true \
      --api-versions agents.x-k8s.io/v1beta1/Sandbox \
      --api-versions extensions.agents.x-k8s.io/v1beta1/SandboxWarmPool
    

    kind: SandboxWarmPool renders with replicas: 2, and the Role gains sandboxclaims with get, list, create, delete.

  2. Build a sandbox provider with a recording fetchImpl, as server/tests/computer-sandbox.test.ts already does, and call locate for a Bot with no computer. The three requests above are all of them.

  3. grep -rn sandboxclaim server/ returns nothing.

Why it matters

The pool is off by default, so this costs nobody who leaves it alone. The people it does reach are the ones who read the values comment, decided the first-action wait was worth paying for, and turned it on. They get the bill — two idle browsers, their nodes and their volumes — and none of the latency they bought it for. Nothing logs a warning, the pool reports healthy, and the only visible symptom is that cold starts feel exactly as slow as before.

The RBAC grant makes it read as finished. A reviewer checking whether claims are permitted finds that they are.

Three ways to close it

Implement claiming: have the sandbox provider create a SandboxClaim and adopt what the controller hands back, instead of posting a fresh Sandbox. That is what the chart was written for and clearly the right end state.

Or delete the switch — warmpool.yaml, sandbox-template.yaml, the sandboxclaims grant and the unreachable warm?() hook — so nothing offers an option that does not do anything.

Or, in between, make the chart refuse to render with the pool on and say why, keeping every template for when claiming lands. That is the treatment computers.mode: sandbox already gets on a cluster with no Sandbox CRD, and the argument is stronger here: the CRD case at least fails at the first browser action, while this one never fails at all.

I have the third written and tested, because it is the one I can prove without guessing at a SandboxClaim schema that this repository does not describe. Happy to send either of the others instead if claiming is close, or if the feature should simply go.

Severity

Low to moderate. Nothing breaks and the default is off. It is money spent for no effect, on an option whose whole purpose is the thing it fails to deliver.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions