Skip to content

flake: rpc-host-gc 'removes an uncleanly killed endpoint' finds nothing to remove (CI, unrelated PR) #4119

Closed

Description

@code-yeongyu

Summary

packages/coding-agent/test/rpc-host-gc.test.ts: the case gc against real supervised hosts > removes an uncleanly killed endpoint, its socket and its siblings, and keeps the live one beside it failed once in CI on a PR that touches no RPC host or gc code.

Evidence

Expected

The case passes deterministically. gc removes the killed endpoint's record, socket and siblings, and keeps the live host.

Hypothesis (unverified)

The test drives real supervised host processes. If gc runs before the killed host's death is observable (its pid still answers, or the lock or socket is not released yet), gc correctly treats the endpoint as live and removes nothing. That would make the case timing-dependent on a loaded runner, like #2876 (a different case in the same file).

Related

Activity

  1. code-yeongyu commented on Oct 24, 2026

    @code-yeongyu
    OwnerAuthor

    Sibling in the same family flaked on CI for an unrelated PR (senpi#4109, which touches only the subscription-limit store): test/rpc-host-gc.test.ts > gc against real supervised hosts > removes an endpoint whose supervisor alone was SIGKILLed, after its host child's watchdog cleaned up, expected removed:[endpoint], got kept:[endpoint]. Run: https://github.com/code-yeongyu/senpi/actions/runs/40051880459/job/120746130698

  2. code-yeongyu commented on Oct 25, 2026

    @code-yeongyu
    OwnerAuthor

    Fixed by #4160 (merge commit f8eeec6a03).

    Root cause. gc read a SIGKILLed supervisor or host child as still running while it was exited but not yet reaped (state Z): kill(pid, 0) succeeds for a zombie and ps -o lstart= still prints its start time, so the generation pidfile matched as live and gc kept the dead endpoint as live_generation. On a loaded runner the reap could land after gc read the pidfile, which is why this flaked rather than failed every time.

    Fix. The identity probe reads state and start time from one ps snapshot and treats state Z as absent; pidfile matching, the host-child check, session-path claim ownership and process-group ownership all treat an unreaped process as exited. Process-group cleanup keeps its previous verdict for a zombie leader (sweep).

    Evidence.

    • Deterministic RED with a real held zombie in a generation host.pid / host-child.pid and as a claim owner: before the fix gc returned removed: [] with live_generation / live_claim, the diff in this issue; reverting only the source change makes every new case fail again.
    • Both cases named here passed 30/30 under three parallel load lanes on macOS; the related real-host suites passed, and CI was green at the merged head.

    The separate flake #2876 (recreated endpoint.json case) is unrelated: an A/B under identical load showed the same rate with and without this change.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions