Skip to content

fix: refuse a service nothing serves; reset every listener at Init; no HTTP in a listener-less image - #115

Merged
antoinetoussaint-byte merged 1 commit into
mainfrom
fix/connect-only-followups
Oct 26, 2026
Merged

antoinetoussaint-byte merged 1 commit into
mainfrom
fix/connect-only-followups

Conversation

@antoinetoussaint-byte

Copy link
Copy Markdown
Contributor

Follow-ups to #113 from its review (r76). Each one is a fix in the agent that owns the behaviour.

  1. A service nothing would serve is refused at Load, by name. This applies when a service has no HTTP endpoint (api: rest / api: http) and no gRPC endpoint for grpc-server to serve. Builder and runtime Load both return nothing would serve this service: … (Service.unservedError). Before, a manifest that lost its endpoints loaded, and Start launched a process with nothing to wait on.
  2. Init resets every listener it publishes. The gRPC and Connect ports and addresses are now cleared together with the HTTP ones, so a reload that drops an endpoint cannot leave Start binding or waiting on it.
    • TestGRPCOnlyStartWaitsOnTheGRPCServer drives Init and Start for a gRPC-only service and checks that readiness waits on the address Init resolved.
    • TestInitDropsTheListenersAReloadRemoved runs Init with a Connect face, then again without it. Start then waits on gRPC only, and the process gets no CODEFLY_CONNECT_PORT.
  3. The image of a service with no HTTP endpoint serves no HTTP. The Dockerfile starts uvicorn on 127.0.0.1 with port 0, as a native start does, instead of 0.0.0.0:8080 (DockerTemplating.NoHTTPEndpoint). An HTTP service's Dockerfile is byte-identical: the existing goldens pass unchanged. TestImageServesNoHTTPWithoutAnHTTPEndpoint checks the new case.

Each new test fails with its line removed. I checked this for the gRPC address store, the Connect reset, and the builder and runtime refusals, one at a time.

Reused: core's FindEndpointsByAPI, the existing Init/Start fakes, the recipe and golden helpers, and #113's mapping helper. Nothing new beyond the three checks.

Checks

  • Pass locally: go build, go vet, gofmt, go mod tidy -diff, go test ./... (Docker and uv tests included) and go test -race -short ./....
  • One full-suite run failed TestConnectOnlyServiceStarts once, from fix: a service whose faces are gRPC and Connect alone loads, syncs and starts #113, and I did not capture why. It passed 6 of 6 runs in isolation and on a full-suite rerun, so I could not reproduce it.
  • Not verified: building and running a real image of a service with no HTTP endpoint. Only the rendered Dockerfile is tested.

🤖 Generated with Claude Code

…o HTTP in a listener-less image

Follow-ups to #113's review (r76):

- Load (builder and runtime) refuses a service with no HTTP endpoint and no
  gRPC endpoint for grpc-server to serve, by name: a manifest that lost its
  endpoints no longer starts a process nothing reaches.
- Init resets the gRPC and Connect ports and addresses with the HTTP ones, so
  a reload that drops an endpoint cannot leave Start binding or waiting on it.
  The gRPC-only readiness path is now tested through Init and Start.
- The Dockerfile of a service with no HTTP endpoint starts uvicorn on a
  loopback port the system picks, as a native start does, instead of binding
  0.0.0.0:8080. The goldens of an HTTP service are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@antoinetoussaint-byte
antoinetoussaint-byte merged commit cf0677b into main Oct 26, 2026
4 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.

1 participant