Skip to content

fix(runtime): stop closing s.Events in Stop; use Base.StopWatcher - #3

Merged
AntoineToussaint merged 1 commit into
mainfrom
fix/watcher-double-close-stopwatcher
Jul 10, 2026
Merged

fix(runtime): stop closing s.Events in Stop; use Base.StopWatcher#3
AntoineToussaint merged 1 commit into
mainfrom
fix/watcher-double-close-stopwatcher

Conversation

@AntoineToussaint

Copy link
Copy Markdown
Contributor

Same double-close-on-shutdown bug as codefly-dev/core#49 (merged): s.Events was closed by both code.Watcher.Start's defer close and Runtime.Stop, racing into panic: close of closed channel and crashing the agent on teardown/Ctrl-C. Stop now calls s.Base.StopWatcher() (cancels the watcher; its deferred close runs once) instead of closing the channel itself.

Builds via the shared go.work today; the go.mod core bump to a version containing services.Base.StopWatcher lands with the next core publish.

🤖 Generated with Claude Code

The events channel is closed by code.Watcher.Start's `defer close` (the
sole sender/closer). Stop also closing it raced that goroutine into a
"close of closed channel" panic on shutdown, crashing the agent. Cancel
the watcher via Base.StopWatcher() and let its deferred close run once.

Requires core with services.Base.StopWatcher (codefly-dev/core#49); the
go.mod bump lands with the next core publish.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@slopbuster

slopbuster Bot commented Jul 10, 2026

Copy link
Copy Markdown

💳 Subscription Required

codefly-dev has used all free reviews this month.

Subscribe to continue

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AntoineToussaint, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 23 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ba4344f1-cf1e-4f7e-82e9-76e4a67066b5

📥 Commits

Reviewing files that changed from the base of the PR and between 8ca36af and db9ba63.

📒 Files selected for processing (1)
  • runtime.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/watcher-double-close-stopwatcher

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AntoineToussaint
AntoineToussaint merged commit dd8ba0d into main Jul 10, 2026
1 check failed
@AntoineToussaint
AntoineToussaint deleted the fix/watcher-double-close-stopwatcher branch July 10, 2026 15:50
antoinetoussaint-byte added a commit that referenced this pull request Aug 25, 2026
…-safe (#14)

Addresses review findings on the optional gRPC server.

#1 (main.py): the grpc server was imported at module top level, so importing
src.main required the generated stubs. Runtime.Init runs GenerateOpenAPI, which
imports src.main *before* Sync generates those stubs (and they are git-ignored,
so a fresh clone has none) — Init failed with ModuleNotFoundError. The import
now lives inside the startup handler; OpenAPI generation never fires startup, so
the module imports cleanly without stubs.

#2 (proto location): the proto was scaffolded at code/proto/api.proto, but
core's LoadEndpoints re-derives the gRPC contract from standards.ProtoPath
(proto/api.proto at the service root) and the manifest stores no proto bytes.
The endpoint therefore reloaded with zero RPCs and dependent services could not
generate clients. The proto now lives at the service-root standard path (Buf and
grpcEndpoint read it there), and defaultProtoPath is bound to standards.ProtoPath
so it can never drift again.

#3 (server.py): add_insecure_port returns 0 instead of raising when a port can't
be bound, so the server would "start" listening on nothing while FastAPI stayed
healthy. It now raises, which also fails the pod's HTTP readiness probe via the
shared lifespan (covers the gRPC-readiness gap).

Tests: added a reload regression test asserting the gRPC endpoint keeps its RPCs
after LoadEndpoints (would have caught #2), and a check that src.rpc is never
imported at module top level (would have caught #1).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
antoinetoussaint-byte added a commit that referenced this pull request Aug 26, 2026
* feat: add optional Python gRPC server and proto scaffolding (#14)

Add an opt-in, service-owned grpc.aio listener to the generated FastAPI
service. It runs in the same process as the FastAPI app (booted from the
lifespan), on its own internal port, and stays entirely off by default so
existing REST-only services and their generated layout are unchanged.

- grpc-server settings (enabled/proto) + a creation question, disabled by
  default.
- Scaffold proto/api.proto, Buf config, a grpc.aio server, a gRPC health
  service, and a user-owned servicer seam when enabled.
- Regenerate the Python protobuf + gRPC stubs from the proto during Sync.
- Create/load a Codefly gRPC endpoint in Builder and Runtime; wire native,
  container, and Kubernetes port mappings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: place gRPC proto at core-standard path and make grpc boot import-safe (#14)

Addresses review findings on the optional gRPC server.

#1 (main.py): the grpc server was imported at module top level, so importing
src.main required the generated stubs. Runtime.Init runs GenerateOpenAPI, which
imports src.main *before* Sync generates those stubs (and they are git-ignored,
so a fresh clone has none) — Init failed with ModuleNotFoundError. The import
now lives inside the startup handler; OpenAPI generation never fires startup, so
the module imports cleanly without stubs.

#2 (proto location): the proto was scaffolded at code/proto/api.proto, but
core's LoadEndpoints re-derives the gRPC contract from standards.ProtoPath
(proto/api.proto at the service root) and the manifest stores no proto bytes.
The endpoint therefore reloaded with zero RPCs and dependent services could not
generate clients. The proto now lives at the service-root standard path (Buf and
grpcEndpoint read it there), and defaultProtoPath is bound to standards.ProtoPath
so it can never drift again.

#3 (server.py): add_insecure_port returns 0 instead of raising when a port can't
be bound, so the server would "start" listening on nothing while FastAPI stayed
healthy. It now raises, which also fails the pod's HTTP readiness probe via the
shared lifespan (covers the gRPC-readiness gap).

Tests: added a reload regression test asserting the gRPC endpoint keeps its RPCs
after LoadEndpoints (would have caught #2), and a check that src.rpc is never
imported at module top level (would have caught #1).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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