Skip to content

feat(cloud-agent-next): add container lifecycle logging - #4898

Merged
St0rmz1 merged 1 commit into
mainfrom
feat/container-lifecycle-logging
Jul 30, 2026
Merged

feat(cloud-agent-next): add container lifecycle logging#4898
St0rmz1 merged 1 commit into
mainfrom
feat/container-lifecycle-logging

Conversation

@St0rmz1

@St0rmz1 St0rmz1 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Container runs in cloud-agent-next have no log in the worker when they start.
onStart logs only on the failure path (missing attribution), so there is no
record that a container began, why it began, or how long it ran. Answering
questions about container lifetime currently means correlating usage rows
against worker logs by hand, including decoding the epoch suffix out of a
container name to find the join key.

This adds structured lifecycle logging. Logging only, no behavior change.

New log tags:

  • container_started (info) in container-usage.ts, emitted from
    startBillingGeneration with generation, startEpochMs, sandboxClass,
    durableObjectId, and a trigger field that distinguishes a real SDK
    onStart from the two paths that adopt an already running container.
  • container_stopped (info) in onStop, carrying stop reason, exitCode,
    and lifetimeMs.
  • wrapper_stop_inspection (info) in CloudflareAgentSandbox.stopWrappers,
    recording the observation outcome (present, absent, inspection-failed)
    and the observed wrapper count for each stop attempt.
  • sandbox_keepalive_renewed (debug) in the ingest heartbeat debounce, with
    sinceLastRenewalMs.
  • idle_kilo_server_stopped added to the existing "Stopping idle kilo server"
    log, along with a new overdueMs field measuring how late the sweep ran
    against its own idleTimeoutMs.

The two silent early returns in keepSandboxAlive (agent-runtime.ts) now log
which guard tripped. Both previously returned without any log, which in Axiom
was indistinguishable from a renewal that succeeded.

container_started and container_stopped both carry generation and
startEpochMs. With sandboxId these form the usage intervalId
(service:instanceId:startEpochMs, see packages/container-usage/src/contracts.ts),
so a log line now joins directly to its usage row.

Verification

  • No manual testing. Every change is a log statement on an existing code
    path with no behavior change, and the paths involved (container start and
    stop, wrapper stop inspection, ingest heartbeat) are driven by sandbox
    lifecycle events rather than by request input.

Visual Changes

N/A

Reviewer Notes

  • wrapper_stop_inspection is the one worth a closer look. stopWrappers
    inspects by calling listProcesses, which is a container fetch, so it wakes a
    sleeping container. Logging the observation outcome makes it measurable how
    often a stop attempt boots a container only to find no wrapper running. This
    PR measures that, it does not change it.
  • Log volume: container_started and container_stopped fire once per container
    run. wrapper_stop_inspection fires once per wrapper stop attempt. Idle
    timeout stop reconciles alone currently run roughly 320 to 580 per hour, and
    other stop reasons add to that. sandbox_keepalive_renewed is debug level and
    fires at most once per 30 second heartbeat debounce per connected wrapper.
  • startBillingGeneration gained a required trigger parameter. All three call
    sites are updated.
  • Checks: typecheck, oxlint, and workspace format:check pass. 991 unit tests
    pass across the five touched modules. Two failures in
    test/unit/wrapper/server.test.ts (git co-author tests, 5s timeouts) are
    pre-existing and reproduce on main without these changes.

@kilo-code-bot

kilo-code-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Observability-only change adding container_started/container_stopped/wrapper_stop_inspection/sandbox_keepalive_renewed log lines plus a ContainerStartTrigger parameter; no control-flow, billing, or lifecycle semantics change, and confidence is high.

Verification notes
  • startBillingGeneration gained a required trigger argument and all three call sites (configure-billing adoption, onStart, replacement generation) pass a valid literal.
  • logger.withTags keys used (logTag, sessionId, sandboxId) all exist in CloudAgentTags, matching existing usage in sandbox-recovery.ts and workspace-backup-observability.ts.
  • await this.resolveSandboxId() inside the stopWrappers log is served from the cached promise already resolved by getSandbox() on the previous line, so it adds no extra container round-trip and cannot change the early-return path.
  • sinceLastRenewalMs in ingest.ts is computed before lastHeartbeatUpdate is overwritten, and the attachment field is initialized to now at connect, so no bogus epoch-sized first value.
  • New logs carry only session/sandbox/generation identifiers — no tokens, headers, or PII.
  • Static review only: repository typecheck/test suites were not run in this environment.
Files Reviewed (5 files)
  • services/cloud-agent-next/src/agent-sandbox/cloudflare/cloudflare-agent-sandbox.ts
  • services/cloud-agent-next/src/container-usage.ts
  • services/cloud-agent-next/src/persistence/CloudAgentSession.ts
  • services/cloud-agent-next/src/session/agent-runtime.ts
  • services/cloud-agent-next/src/websocket/ingest.ts

Reviewed by claude-opus-5 · Input: 50 · Output: 9K · Cached: 1.6M

Review guidance: REVIEW.md from base branch main

@St0rmz1
St0rmz1 merged commit 66eb6e1 into main Jul 30, 2026
16 checks passed
@St0rmz1
St0rmz1 deleted the feat/container-lifecycle-logging branch July 30, 2026 17:00
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