Skip to content

Add built-in /health and /ready endpoints to the Pro node renderer#3939

Merged
justin808 merged 17 commits into
mainfrom
jg/3880-node-renderer-health-ready
Jun 15, 2026
Merged

Add built-in /health and /ready endpoints to the Pro node renderer#3939
justin808 merged 17 commits into
mainfrom
jg/3880-node-renderer-health-ready

Conversation

@justin808

@justin808 justin808 commented Jun 11, 2026

Copy link
Copy Markdown
Member

Summary

Adds first-class, opt-in liveness/readiness probe endpoints to the Pro node renderer, per the maintainer-triaged descope on the issue. Closes #3880.

  • GET /health (liveness): 200 with a status-only body whenever the event loop is responsive; intentionally checks no dependencies.
  • GET /ready (readiness): 503 ({"status":"waiting_for_bundle"}) until the answering worker is online and has at least one server bundle compiled into its VM pool, then 200.
  • Default off; enabled via the new enableHealthEndpoints config option or RENDERER_ENABLE_HEALTH_ENDPOINTS=true.
  • Unauthenticated like /info (orchestrator probes can't carry the renderer password) but expose no runtime version/path/license details.
  • Keeps h2c: no HTTP/1.1 side-listener. New docs page documents working tcpSocket + exec (curl --http2-prior-knowledge) probes for Kubernetes, ECS, and Docker Compose, plus per-worker and cold-start semantics.

Codex Decision Log

  • Non-blocking: where the routes live and what "workers online" means
    • Decision: routes registered in worker.ts (the master never listens); a probe being answered proves the answering worker is up; per-worker semantics documented
    • Why: matches the existing /info route placement and cluster architecture
    • Review later: None
  • Non-blocking: what "≥1 bundle loaded" means
    • Decision: "compiled into the VM pool" (hasAnyVMContext()), not "present in the disk cache"
    • Why: the strict reading; stale on-disk bundles would over-report readiness
    • Review later: the resulting cold-start caveat and traffic-gating guidance in the docs page
  • Non-blocking: Kubernetes example readiness gate (codex review finding, addressed)
    • Decision: the main example uses a shallow tcpSocket readiness probe; gating traffic on /ready is documented as a separate option that requires a warm-up render path, with the deadlock failure mode (no traffic → no first render → never ready, including the sidecar/pod-readiness case) spelled out
    • Why: gating cold replicas on /ready with no pre-warm path deadlocks rollouts
    • Review later: None
  • Per triage cuts: no license check (Rails-side only), no token auth, no Rails preflight helper, no pool-saturation counters, no HTTP/1.1 listener.
  • docs/oss/deployment/docker-deployment.md intentionally untouched — its broken httpGet probe is fixed by Docs: fix Node Renderer Kubernetes probes #3930; this PR's docs are written to be consistent with it.

Test plan

  • New tests/healthEndpoints.test.ts: 404 when disabled; /health 200 status-only; /ready 503→200 transition through a real render-with-bundle request; /health stable across bundle state. All pass locally.
  • pnpm run lint, pnpm run type-check, pnpm run build, pnpm start format.listDifferent, script/check-docs-sidebar origin/main, script/check-pro-license-headers: all pass.
  • Full package jest suite: 331 pass; the 31 failures in 5 suites are environment-only and reproduce identically on clean origin/main (no local redis, streaming timeouts).
  • codex review --base origin/main: two P2 findings (k8s readiness deadlock guidance, changelog placeholder link) — both addressed in follow-up commits.

🤖 Generated with Claude Code

Merge Readiness Criteria

Current evaluation as of 2026-06-15 for head a7368575c1d0fe6c01497013173fe98ca32b9cd4.

  • Release mode: accelerated-rc, confirmed live from canonical release gate Release gate: react_on_rails 17.0.0 #3823 (Mode: accelerated-rc).
  • Current head SHA: a7368575c1d0fe6c01497013173fe98ca32b9cd4.
  • CI/check status: Current-head gh pr checks 3939 --repo shakacode/react_on_rails --json bucket reports 45 passing checks and 6 expected path-selected/skipped checks; no pending or failing checks. mergeStateStatus is CLEAN.
  • Review-thread status: Paginated GraphQL review-thread sweep reports 44 total threads and unresolved=0.
  • Review feedback triage: Fixed the shared-truthy() behavioral concern by restoring the helper to origin/main behavior and scoping 1 parsing to RENDERER_ENABLE_HEALTH_ENDPOINTS; added CodeQL missing-rate-limiting suppressions for /health and /ready; skipped the optional native Error { cause } style cleanup because local type-check rejects it under the package current TS/lib target; acknowledged the non-actionable createdApp?.close() note.
  • Validation run: pnpm --dir packages/react-on-rails-pro-node-renderer exec jest tests/healthEndpoints.test.ts tests/configBuilder.test.ts --runInBand -> 53/53 pass; pnpm --dir packages/react-on-rails-pro-node-renderer run type-check -> pass; node script/generate-llms-full.mjs --check -> pass; pnpm start format.listDifferent -> pass; script/check-docs-sidebar origin/main -> pass; script/check-pro-license-headers -> pass; script/ci-changes-detector origin/main -> Pro node-renderer package path detected; pnpm run build -> pass; pnpm run lint -> pass; git diff --check --no-ext-diff -> pass; (cd react_on_rails && BUNDLE_GEMFILE=../Gemfile bundle exec rubocop) -> pass/no offenses; branch autoreview against origin/main -> clean; pre-commit and pre-push hooks -> pass.
  • Label/CI decision: Labels: full-ci. This remains appropriate because the PR touches Pro node-renderer health/readiness behavior. No benchmark label recommended because the endpoints are opt-in, status-only probes and do not affect render throughput paths.
  • Known residual risk: No unresolved review thread or failing check remains. Accelerated-RC independent finalizer/confidence gate is not satisfied by this author/coordinator session.
  • Merge recommendation: Ready for maintainer/independent finalizer. Do not auto-merge from this session under accelerated-RC finalizer rules.

Note

Medium Risk
Touches production deployment probes and readiness semantics (per-worker, bundle-compilation gate); misconfigured readiness on /ready can deadlock rollouts, though docs call this out and the feature is opt-in.

Overview
Pro node renderer gains opt-in built-in GET /health (liveness, always 200 when the worker responds) and GET /ready (readiness: 503 until the answering worker has at least one bundle compiled in its VM pool via new hasAnyVMContext(), then 200). Both are off by default and turned on with enableHealthEndpoints or RENDERER_ENABLE_HEALTH_ENDPOINTS (true/yes/1, with 1 scoped only to this flag).

Routes register on the worker Fastify app (like /info), return status-only JSON, and run before configureFastify; conflicting custom /health or /ready routes get a clearer migration error when FST_ERR_DUPLICATED_ROUTE matches.

Documentation adds a health-checks guide (h2c / tcpSocket + exec probes, cold-start and /ready traffic-gating caveats) and updates js-configuration and the docs sidebar; CHANGELOG and llms-full are updated accordingly.

Reviewed by Cursor Bugbot for commit df10515. Bugbot is set up for automated code reviews on this repo. Configure here.

Agent Merge Confidence

Mode: accelerated-rc
Current head SHA: df10515
Score: 8/10
Auto-merge recommendation: yes; maintainer-directed merge requested after conflict resolution
Affected areas: React on Rails Pro node renderer health/readiness endpoints, node renderer docs, generated llms reference
CI detector: script/ci-changes-detector origin/main -> Pro node renderer package; recommends lint, Pro lint/specs/dummy integration, node-renderer tests, and benchmark coverage.
Validation run:

  • node script/generate-llms-full.mjs && node script/generate-llms-full.mjs --check -> passed after conflict resolution.
  • git diff --check -> passed after conflict resolution.
  • Pre-push hooks on resolved head -> RuboCop branch lint passed; Markdown link checks passed with lychee 0.23.0.
    Review/check gate:
  • GitHub checks: complete for df105150098f2e7adb6c41cf9a4ee5dc53c7ab3d; 45 passed, 5 expected selector/placeholder skips, 0 failed.
  • Review threads: GraphQL unresolved count is 0.
  • Current-head reviewer verdicts:
    • Claude review: passed for current head.
    • Cursor Bugbot: passed for current head.
    • CodeRabbit: passed for current head.
      Known residual risk: low; node renderer readiness/health endpoint behavior is covered by the package checks, but this remains a release-candidate infrastructure path.
      Finalized by: maintainer-directed merge requested by @justin808 in Codex session on 2026-06-15; this is not an autonomous accelerated-RC merge.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR introduces built-in health and readiness probe endpoints (/health and /ready) for the React on Rails Pro node renderer. The feature adds a new enableHealthEndpoints configuration option that gates registration of unauthenticated endpoints: /health provides event-loop liveness detection, and /ready returns readiness only when at least one compiled bundle is available. It includes comprehensive documentation for Kubernetes, ECS, and Docker Compose deployments, and full test coverage.

Changes

Built-in Health and Readiness Endpoints

Layer / File(s) Summary
Configuration Schema and Defaults
packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts
Config interface adds enableHealthEndpoints: boolean, derived from RENDERER_ENABLE_HEALTH_ENDPOINTS env var via truthy. Default config initialization, diagnostics tracking, and buildConfig coerce env-derived values to boolean.
Readiness State Check Helper
packages/react-on-rails-pro-node-renderer/src/worker/vm.ts
Exports hasAnyVMContext() helper to report whether the worker has any compiled bundle VM contexts loaded; used by readiness endpoint to determine ready status.
Health and Readiness Route Handlers
packages/react-on-rails-pro-node-renderer/src/worker.ts
Worker imports readiness helper, destructures enableHealthEndpoints from config, defines route conflict migration helpers, conditionally registers /health (always 200 ok) and /ready (200 ready or 503 waiting_for_bundle based on bundle availability), and wraps FastifyConfig with conflict detection.
Health Endpoint Tests
packages/react-on-rails-pro-node-renderer/tests/healthEndpoints.test.ts
Jest tests verify endpoints are 404 unregistered by default, /health returns 200 ok when enabled, /ready transitions from 503 (before bundle) to 200 (after first render compiles bundle), and conflicting custom routes throw startup errors.
Documentation and Reference
docs/oss/building-features/node-renderer/health-checks.md, docs/oss/building-features/node-renderer/js-configuration.md, docs/sidebars.ts, CHANGELOG.md
New health-checks page documents enablement, h2c vs HTTP/1.1 probe compatibility, Kubernetes/ECS/Docker Compose examples, caveats, and Rails alignment; updates js-configuration guidance; adds sidebar entry and changelog note.

Sequence Diagram

sequenceDiagram
  participant Client
  participant HealthRoute
  participant ReadyRoute
  participant hasAnyVMContext
  Client->>HealthRoute: GET /health
  HealthRoute->>Client: 200 { status: 'ok' }
  Client->>ReadyRoute: GET /ready
  ReadyRoute->>hasAnyVMContext: check if contexts exist
  hasAnyVMContext-->>ReadyRoute: true/false
  alt Has Bundle
    ReadyRoute->>Client: 200 { status: 'ready' }
  else Waiting for Bundle
    ReadyRoute->>Client: 503 { status: 'waiting_for_bundle' }
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • shakacode/react_on_rails#3241: Main PR introduces opt-in built-in /health//ready probe endpoints and updates js-configuration.md semantics, while the retrieved PR updates node-renderer health-probe documentation and curl/h2c probe commands.

Suggested labels

enhancement, review-needed, documentation, P2

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the main change: adding built-in /health and /ready endpoints to the Pro node renderer, which is the primary focus of all code changes.
Linked Issues check ✅ Passed All core objectives from issue #3880 are met: /health endpoint returns 200 when responsive, /ready returns 503/200 based on bundle state, opt-in via enableHealthEndpoints config and RENDERER_ENABLE_HEALTH_ENDPOINTS env var, status-only unauthenticated JSON responses, h2c documentation with probe examples, and comprehensive test coverage validating endpoint behavior.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing health/readiness endpoints: config additions, endpoint registration, VM context detection helper, comprehensive documentation with Kubernetes/ECS/Docker examples, tests, sidebar registration, and changelog entry. No unrelated refactoring or feature additions.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg/3880-node-renderer-health-ready

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 and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4b5f62aa63

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/oss/building-features/node-renderer/health-checks.md Outdated
@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds opt-in /health (liveness) and /ready (readiness) endpoints to the Pro node renderer, enabled via enableHealthEndpoints: true or RENDERER_ENABLE_HEALTH_ENDPOINTS=true. The implementation is clean, well-tested, and consistent with the existing /info route pattern.

  • Core change: Routes registered in worker.ts behind an enableHealthEndpoints guard; /ready uses a new hasAnyVMContext() helper in vm.ts to gate on at least one compiled bundle.
  • Config: enableHealthEndpoints follows the same truthy() coercion and 'in userConfig' guard pattern used by supportModules and other boolean options in configBuilder.ts.
  • Docs: New health-checks.md page correctly covers the h2c/HTTP1.1 probe incompatibility, per-worker semantics, the cold-start deadlock caveat for Kubernetes readiness gates, and working tcpSocket/exec probe examples; CHANGELOG.md entry still contains the [PR XXXX] placeholder.

Confidence Score: 4/5

Safe to merge; the new routes are off by default and the implementation is tightly scoped with good test coverage.

The CHANGELOG placeholder link is still XXXX and there is no startup-time guard against route conflicts when enableHealthEndpoints is combined with a pre-existing custom /health via configureFastify — a user migrating from the documented recipe to the new built-in will get a Fastify startup crash without a helpful error message.

CHANGELOG.md (placeholder PR link) and the route registration block in worker.ts (migration conflict risk with existing configureFastify /health routes).

Important Files Changed

Filename Overview
packages/react-on-rails-pro-node-renderer/src/worker.ts Adds opt-in /health and /ready GET routes inside the enableHealthEndpoints guard; correct Fastify reply API usage and placement mirrors the existing /info route.
packages/react-on-rails-pro-node-renderer/src/worker/vm.ts Adds hasAnyVMContext() — a single-line Map.size check — to expose bundle-load state for the /ready probe; no logic changes to existing VM lifecycle.
packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts Adds enableHealthEndpoints field and default; uses the same truthy() coercion and 'in userConfig' guard pattern as supportModules and other boolean options.
packages/react-on-rails-pro-node-renderer/tests/healthEndpoints.test.ts New test suite covers 404-when-disabled, /health 200, /ready 503→200 transition via a real bundle upload, and /health stability across bundle states.
docs/oss/building-features/node-renderer/health-checks.md New docs page covering h2c probe limitations, Kubernetes/ECS/Docker Compose examples, cold-start/per-worker semantics, and the deadlock caveat for /ready as a readiness gate.
docs/oss/building-features/node-renderer/js-configuration.md Adds enableHealthEndpoints to the option list and updates the readiness probe section to prefer the new built-in /ready endpoint.
docs/sidebars.ts Inserts health-checks into the node-renderer sidebar section after container-deployment.
CHANGELOG.md Adds feature entry with correct description; PR link placeholder [PR XXXX] still needs to be replaced with 3939.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Probe request arrives] --> B{enableHealthEndpoints?}
    B -- false --> C[404 Not Found]
    B -- true --> D{Route?}
    D -- GET /health --> E[200 status: ok\nEvent loop is responsive]
    D -- GET /ready --> F{hasAnyVMContext?}
    F -- yes\nat least one bundle compiled --> G[200 status: ready]
    F -- no\nno bundle yet --> H[503 status: waiting_for_bundle]
    D -- other --> I[Handled by existing routes]
Loading

Reviews (1): Last reviewed commit: "Fill in PR number in changelog entry" | Re-trigger Greptile

Comment thread CHANGELOG.md Outdated
Comment thread packages/react-on-rails-pro-node-renderer/src/worker.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/oss/building-features/node-renderer/js-configuration.md`:
- Line 51: Update the docs for enableHealthEndpoints to reflect that the
renderer uses the truthy(...) parser rather than raw JS truthiness: replace the
default expression text `env.RENDERER_ENABLE_HEALTH_ENDPOINTS || false` with
wording that it uses `truthy(env.RENDERER_ENABLE_HEALTH_ENDPOINTS)` (or
equivalent phrase) so readers know string values like "false" are interpreted
via the truthy helper (see configBuilder.ts and the truthy usage in the
enableHealthEndpoints handling).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 13dfa47a-9b78-4d0f-b1a0-5aae487430d4

📥 Commits

Reviewing files that changed from the base of the PR and between 661c6fa and 4b5f62a.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • docs/oss/building-features/node-renderer/health-checks.md
  • docs/oss/building-features/node-renderer/js-configuration.md
  • docs/sidebars.ts
  • packages/react-on-rails-pro-node-renderer/src/shared/configBuilder.ts
  • packages/react-on-rails-pro-node-renderer/src/worker.ts
  • packages/react-on-rails-pro-node-renderer/src/worker/vm.ts
  • packages/react-on-rails-pro-node-renderer/tests/healthEndpoints.test.ts

Comment thread docs/oss/building-features/node-renderer/js-configuration.md Outdated
@claude

claude Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Code Review — PR #3939: Built-in /health and /ready endpoints

Overall: solid, low-risk addition. The implementation is clean, defaults-off, and follows the existing /info route pattern. The documentation is the real work here and is comprehensive. A few things worth addressing before merge:


Architecture & Correctness

Per-worker VM state is correct. hasAnyVMContext() reads vmContexts.size from the module-level Map, which is separate per worker process in a Node.js cluster. A probe returns readiness for the single worker that answered it — this is the right semantic and the docs explain it clearly.

Route registration order matters. Built-in health routes are registered (lines 670–686) before applyFastifyConfigFunctions(app) (line 706). If a user currently has a custom /health route in configureFastify and enables enableHealthEndpoints: true, Fastify will throw a duplicate-route error at startup. The docs mention "different paths" in the Semantics section, but a migration note near the built-in alternative callout in js-configuration.md would help users who are actually upgrading from the configureFastify recipe.

truthy() does not handle "1" or "on". The env var reads RENDERER_ENABLE_HEALTH_ENDPOINTS=true. Docs are consistent about using 'true', but this is a pre-existing truthy() limitation across the whole config — fine to leave as-is.


Code Quality

hasAnyVMContext() return type. hasVMContextForBundle (line 63 of vm.ts) also lacks an explicit : boolean annotation, so the new function is consistent with the file's existing style. No change needed.

res.status(503).send(...) vs res.code(503).send(...). Fastify's canonical method is .code(), but .status() is an alias and the existing setResponse helper (line 98 of worker.ts) already uses .status(). Consistent — no change needed.


Tests

Tests are well-structured and cover the key behaviors:

  • 404 when disabled ✓
  • /health returns { status: "ok" } regardless of bundle state ✓
  • /ready 503 → 200 transition through a real bundle upload ✓

One gap: there's no test for RENDERER_ENABLE_HEALTH_ENDPOINTS=true activating the endpoints through the env var path (only through the config object option). Low priority since truthy() is tested independently, but worth noting.


Documentation

The h2c / httpGet won't work section is excellent — this is exactly the footgun users will hit first. The Kubernetes readiness deadlock warning is thorough and the decision to default to tcpSocket in the example is the right call.

Minor --max-time inconsistency (inline comment below): ECS and Kubernetes use --max-time 3; Docker Compose uses --max-time 2. No functional difference, but a reader setting up both will notice it.


Summary

No blocking issues. Two suggestions worth a follow-up before merge:

  1. Add a brief migration note to the js-configuration.md built-in-alternative callout about removing existing /health routes from configureFastify before enabling enableHealthEndpoints.
  2. Align Docker Compose --max-time 23 with the other examples.

Everything else looks good to go.

Comment thread docs/oss/building-features/node-renderer/health-checks.md Outdated
Comment thread docs/oss/building-features/node-renderer/js-configuration.md
@claude

claude Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Code Review

Overall: Clean, well-scoped implementation. The feature is additive and off by default, the docs are thorough, and the test coverage hits the key transitions. A few things worth addressing before merge.

Security

Authentication model is correct. Auth in this codebase is applied per-route via explicit authenticate() calls in each handler — no global hook exists. The new /health and /ready routes correctly omit authenticate(), matching the existing /info pattern. No issue.

Bug / Footgun

Route conflict between enableHealthEndpoints and a pre-existing custom /health via configureFastify.

The built-in /health route is registered at worker.ts line ~670, then applyFastifyConfigFunctions(app) runs at line 706. If a user currently has configureFastify registering their own /health route and then adds enableHealthEndpoints: true, Fastify will throw FST_ERR_DUPLICATED_ROUTE at startup — a crash with no diagnostic message. The docs mention the two "can coexist as long as your custom routes use different paths" but do not call out the exact error or the registration ordering. Worth adding a sentence in the docs and/or a startup warning that names the conflict.

Test Quality

Each test case creates a new app instance but never closes it.

Other tests that hold a long-lived app reference close it in afterAll (see concurrentHtmlStreaming, incrementalRender, streamErrorHang). This test creates a fresh createWorker() per test() — three instances total — and none are closed. With inject()-only usage this rarely causes flakiness, but it leaves open handles that Jest will flag with --detectOpenHandles. Fix: track the app in a let app variable and call app.close() in afterEach.

Minor / Nits

  • envValuesUsed boolean guard is correct and more robust than the existing pattern. Using !('enableHealthEndpoints' in userConfig) correctly suppresses the env var even when the user explicitly passes false. The existing pattern for other options uses !userConfig.field which misfires when the value is deliberately false or 0. This new pattern is worth backfilling to other boolean options in a follow-up.

  • Docs — ECS startPeriod: 30 may be tight for cold-start. The docs' own cold-start note explains that the first bundle compiles on the first render request. Depending on app size 30 s may not be enough; pointing users to tune this value against observed startup time would help.

Summary

Solid PR. The route-conflict footgun is the only real risk — existing configureFastify users who add enableHealthEndpoints will hit a startup crash with no guidance on what to rename. The test cleanup issue is low-risk but inconsistent with the rest of the suite. Everything else is a nit.

Comment thread packages/react-on-rails-pro-node-renderer/src/worker.ts
Comment thread docs/oss/building-features/node-renderer/health-checks.md
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size
react-on-rails/client bundled (gzip) 62.35 KB (0%)
react-on-rails/client bundled (gzip) (time) 62.35 KB (0%)
react-on-rails/client bundled (brotli) 53.49 KB (0%)
react-on-rails/client bundled (brotli) (time) 53.49 KB (0%)
react-on-rails-pro/client bundled (gzip) 63.57 KB (0%)
react-on-rails-pro/client bundled (gzip) (time) 63.57 KB (0%)
react-on-rails-pro/client bundled (brotli) 54.58 KB (0%)
react-on-rails-pro/client bundled (brotli) (time) 54.58 KB (0%)
registerServerComponent/client bundled (gzip) 73.77 KB (0%)
registerServerComponent/client bundled (gzip) (time) 73.77 KB (0%)
registerServerComponent/client bundled (brotli) 63.56 KB (0%)
registerServerComponent/client bundled (brotli) (time) 63.56 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) 66.76 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) (time) 66.76 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) 57.23 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) (time) 57.23 KB (0%)

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size
react-on-rails/client bundled (gzip) 61.41 KB (0%)
react-on-rails/client bundled (gzip) (time) 61.41 KB (0%)
react-on-rails/client bundled (brotli) 52.63 KB (0%)
react-on-rails/client bundled (brotli) (time) 52.63 KB (0%)
react-on-rails-pro/client bundled (gzip) 62.57 KB (0%)
react-on-rails-pro/client bundled (gzip) (time) 62.57 KB (0%)
react-on-rails-pro/client bundled (brotli) 53.69 KB (0%)
react-on-rails-pro/client bundled (brotli) (time) 53.69 KB (0%)
registerServerComponent/client bundled (gzip) 72.73 KB (0%)
registerServerComponent/client bundled (gzip) (time) 72.73 KB (0%)
registerServerComponent/client bundled (brotli) 62.53 KB (0%)
registerServerComponent/client bundled (brotli) (time) 62.53 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) 66.08 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) (time) 66.08 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) 56.65 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) (time) 56.65 KB (0%)

@justin808

justin808 commented Jun 13, 2026

Copy link
Copy Markdown
Member Author

Codex advisory claim update: pushed commit e9960eda8 addressing health endpoint env parsing docs and tightening /health vs /ready ECS cold-start guidance. PR remains not merge-ready: fresh checks/reviews are pending and branch is still DIRTY (worker saw CHANGELOG.md rebase conflict).

@justin808

Copy link
Copy Markdown
Member Author

Refreshing this claim while continuing the closeout batch. Working from current origin/main with #3977 coordination present; avoiding reserved #3963 docs lane.

@justin808 justin808 force-pushed the jg/3880-node-renderer-health-ready branch from e9960ed to b876f08 Compare June 13, 2026 23:29
@claude

claude Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Code Review — PR #3939: Add built-in /health and /ready endpoints to the Pro node renderer

Overview

Solid, well-scoped implementation. The feature is minimal (38 lines of runtime code across two files), opt-in, correctly documented, and fully tested with a real-bundle lifecycle test. The design decisions (unauthenticated like /info, status-only body, no HTTP/1.1 side-listener, routes in worker.ts not the master) are all sound and consistent with the existing codebase.

Strengths

  • Correct opt-in plumbing: enableHealthEndpoints is wired through config, env var, envValuesUsed(), and buildConfig() in exactly the same pattern as existing options. The 'enableHealthEndpoints' in userConfig guard correctly handles enableHealthEndpoints: false (explicit opt-out) without falsely reporting the env var as active.
  • String coercion is safe: applying truthy() in buildConfig() to mirror the supportModules pattern is the right call given JS-land callers can pass env-derived strings.
  • hasAnyVMContext() is the right abstraction: O(1), correctly placed in vm.ts, and well-named.
  • Test coverage matches the design: the 503→200 transition test drives a real render request rather than stubbing the VM state — that is the right fidelity for this readiness check.
  • Documentation is thorough: the h2c / httpGet warning, the deadlock scenario for /ready-gated readiness probes, and the cold-start note are all accurate and clearly written.

Issues

Minor: one test gap — env var activation path

The test suite only exercises enableHealthEndpoints: true via the config object path. There is no test for the env var path (setting RENDERER_ENABLE_HEALTH_ENDPOINTS=true as a process env var and verifying the endpoints are registered). Given the coercion path (truthy(env.RENDERER_ENABLE_HEALTH_ENDPOINTS)) is the one most operators will use via container env vars, a one-line env-var test is worth adding.

Minor: implementation detail in user-facing docs

See inline comment on js-configuration.md.

Observation: per-worker /ready semantics in multi-worker clusters (already documented)

In a cluster with workersCount > 1, consecutive /ready probes can return different results (200 from a warmed worker, 503 from a fresh one) during the cold-start window. The code comment in worker.ts acknowledges this, and the docs correctly steer users toward tcpSocket readiness probes (not /ready) unless they have a pre-warm path. No change needed — this is correct behavior, just confirming the team is comfortable with it as the documented contract.

Verdict

Approve with nits. The runtime change is minimal and correct; the main ask is a one-line env-var test and a docs wording fix (see inline). No blocking issues.

Comment thread docs/oss/building-features/node-renderer/js-configuration.md Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b876f089f3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/oss/building-features/node-renderer/health-checks.md Outdated
@claude

claude Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Code Review

Overall: This is a well-implemented feature. The design decisions (off-by-default, per-worker semantics, status-only response bodies, unauthenticated like /info) are all sound, and the documentation is unusually thorough for a deployment-facing feature. A few things worth flagging.


What's Good

  • Security posture is correct. Endpoints return only { status: ... } — no version strings, file paths, or license info — and are off by default. The unauthenticated design mirrors /info and is appropriate since orchestrator probes can't carry the renderer password.

  • hasAnyVMContext() is the right signal. An O(1) Map.size > 0 check is the right implementation, and it correctly reflects whether the worker can actually serve renders (a disk-cached bundle that hasn't been compiled into a VM context doesn't count). In production the pool is never fully cleared once a bundle is loaded (vmContexts.clear() is only called in test teardown via resetVMContexts), so the 503→200 transition is monotonic in normal operation.

  • 'enableHealthEndpoints' in userConfig in envValuesUsed() is subtly correct: it distinguishes "user explicitly set false" (env var should be ignored) from "user didn't set it at all" (env var should win), avoiding the false-positive you'd get with !userConfig.enableHealthEndpoints.

  • Test coverage is solid. All four meaningful states are tested: disabled (404), enabled via config (200/503/200 transition), enabled via env var, and liveness independent of bundle state. The renderWithBundle helper simulates the actual Rails client path rather than poking internal state directly.

  • Deadlock caveat documentation is excellent. The per-worker semantics and the sidecar pod-readiness deadlock scenario (/ready gates traffic -> no traffic -> no first render -> never ready) are exactly the kind of failure modes that bite users in production and rarely appear in documentation.


Issues / Suggestions

1. Startup probe failureThreshold is tight for a meaningful startup window

In the Kubernetes example:

startupProbe:
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 6

Total startup budget = 10 + (5 x 6) = 40 seconds. For a cold container pulling a large bundle this can be short. failureThreshold on startup probes is the right lever to give slow-starting apps more time without affecting liveness periodicity, and the comment says "shield liveness while the renderer boots" — but 40 s may not cover a cold pull. Consider bumping to failureThreshold: 12 (70 s) and noting that users should tune to their bundle size, or at minimum adding a comment that this is a baseline and not a safe default for all deployments.

2. res.status(503) — consider a Retry-After header

res.status(503) is already used in the codebase (line 98 of worker.ts), so there is no API inconsistency. However, RFC 7231 §6.6.4 recommends a Retry-After header with 503 responses. Adding res.header('Retry-After', '5') would let probes back off intelligently rather than hammering the endpoint every periodSeconds. Not a blocker, but worthwhile polish.

3. Test: env-var test — consider adding a precondition guard

test('GET /health and GET /ready are registered when enabled by environment variable', async () => {
  process.env.RENDERER_ENABLE_HEALTH_ENDPOINTS = 'true';
  app = createWorker();

This is correct as written — beforeEach deletes the env var before each test, then this test sets it before creating the worker. But a defensive expect(process.env.RENDERER_ENABLE_HEALTH_ENDPOINTS).toBeUndefined() at the top of this test would make the precondition explicit and prevent silent breakage if beforeEach ordering ever changes.

4. Docker Compose example: RENDERER_HOST: '0.0.0.0' is unnecessary there

environment:
  RENDERER_HOST: '0.0.0.0'

Docker Compose healthchecks run inside the container (like a Kubernetes exec probe), so localhost resolves correctly — 0.0.0.0 binding is not needed. The Kubernetes section uses it for tcpSocket probes that connect to the pod IP, which is where this note belongs. Leaving it in Docker Compose is harmless, but it may confuse readers who copy the snippet and wonder why they are binding to 0.0.0.0 in a local Compose setup.


Summary

No correctness bugs found. Items 1 and 4 are the most actionable; the rest are optional polish. The overall quality is high — the per-worker semantics and deadlock discussion alone are better than what ships in most infrastructure documentation.

Comment thread docs/oss/building-features/node-renderer/health-checks.md
Comment thread packages/react-on-rails-pro-node-renderer/src/worker.ts Outdated
Comment thread docs/oss/building-features/node-renderer/health-checks.md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2ab91a0ab0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/oss/building-features/node-renderer/js-configuration.md Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c41fe0d8fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CHANGELOG.md Outdated
@justin808 justin808 force-pushed the jg/3880-node-renderer-health-ready branch from 2b50f60 to 98274af Compare June 14, 2026 21:34
@claude

claude Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Review: PR #3939 — Built-in /health and /ready endpoints

Overall this is a well-structured feature addition. The design decisions are sound (opt-in, status-only bodies, consistent with the existing /info approach, clear documentation of the h2c constraint), and the test suite covers the key behavioral transitions. A few observations below.

Correctness

Migration hint only covers synchronous configureFastify callbacks (noted in the applyFastifyConfigWithHealthEndpointMigrationHint comment, but worth surfacing). If a user registers routes using an async Fastify plugin pattern — fastify.register(plugin) inside the configureFastify callback — the duplicate-route error fires asynchronously during app.ready(), after the sync try/catch has already returned. Those users won't get the migration hint message; they'll see a raw Fastify FST_ERR_DUPLICATED_ROUTE. Consider adding a note to the migration callout in the docs (health-checks.md and js-configuration.md) so async-plugin users know what to expect.

truthy() change broadens acceptance for existing env vars: Adding '1' to the accepted values also changes behaviour for RENDERER_SUPPORT_MODULES and REPLAY_SERVER_ASYNC_OPERATION_LOGS (documented in the changelog). This is purely additive — '1' is universally expected to mean "true" in Unix environments — but it's a subtle behaviour change for anyone who happened to rely on '1' being rejected. The CHANGELOG entry covers it, which is the right place.

hasAnyVMContext() semantics are correct and well-documented: The JSDoc's note that the function returns false while compilation is in-flight in vmCreationPromises is the right strict reading. Combined with the validated maxVMPoolSize >= 1 invariant, /ready won't spuriously flip back to 503 after the first bundle loads unless all workers restart.

Minor

  • The READY_RETRY_AFTER_SECONDS = 5 constant is not configurable. That's fine for the common case, but it may be worth noting in docs that orchestrators use this value to schedule re-probes — a very short periodSeconds on the readiness probe combined with a long compilation time could result in many retries before the hint takes effect.
  • The test suite tests the 503→200 transition through a real render-with-bundle request, which is exactly the right level of integration. One small gap: the test matrix for env var values covers ['true', 'TRUE', 'yes', 'YES', '1'] for enabled and ['false', '0'] for disabled, but doesn't cover passing a boolean false directly via createWorker({ enableHealthEndpoints: false }) to verify the coercion path in buildConfig.

Documentation

The health-checks.md page is thorough. The cold-start/deadlock warning under "Gating traffic on /ready" is especially important and clearly written. The per-worker semantics note correctly explains why workersCount > 1 can produce mixed probe responses during startup.

No blocking issues found.

Comment thread packages/react-on-rails-pro-node-renderer/src/shared/truthy.ts Outdated
Comment thread packages/react-on-rails-pro-node-renderer/src/worker.ts
@justin808

justin808 commented Jun 14, 2026

Copy link
Copy Markdown
Member Author

Address-review summary for current head a7368575c1d0fe6c01497013173fe98ca32b9cd4.

Scan scope: review activity after the prior summary cutoff (2026-06-14T22:21:26Z) plus live review-thread state.

Resolved:

Validation evidence:

  • pnpm --dir packages/react-on-rails-pro-node-renderer exec jest tests/healthEndpoints.test.ts tests/configBuilder.test.ts --runInBand -> pass, 53 tests
  • pnpm --dir packages/react-on-rails-pro-node-renderer run type-check -> pass
  • node script/generate-llms-full.mjs --check -> pass
  • pnpm start format.listDifferent -> pass
  • script/check-docs-sidebar origin/main -> pass
  • script/check-pro-license-headers -> pass
  • pnpm run build -> pass
  • pnpm run lint -> pass
  • (cd react_on_rails && BUNDLE_GEMFILE=../Gemfile bundle exec rubocop) -> pass
  • Branch autoreview against origin/main -> clean

Current review-thread state: 0 unresolved threads.

Comment thread packages/react-on-rails-pro-node-renderer/src/shared/truthy.ts Outdated
Comment thread packages/react-on-rails-pro-node-renderer/src/worker.ts
Comment thread packages/react-on-rails-pro-node-renderer/src/worker.ts
@claude

claude Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Code Review

Overall this is a well-designed, well-documented feature. The design decisions (off by default, unauthenticated like /info, status-only bodies, per-worker semantics) are sound and the deadlock risk from gating readiness on /ready without a warm-up path is thoroughly documented. A few items to address before merge:

Must-fix

truthy.ts'1' is a silent behavioural change for existing env vars (see inline).
Adding '1' changes how RENDERER_SUPPORT_MODULES=1 and REPLAY_SERVER_ASYNC_OPERATION_LOGS=1 are interpreted retroactively. Those users don't read the enableHealthEndpoints changelog entry and won't know. At minimum the changelog should surface this change in its own sentence; depending on semver policy it may warrant a minor bump.

worker.ts — CodeQL suppression format (see inline).
// lgtm[...] is the legacy LGTM.com format; GitHub Code Scanning / CodeQL Actions uses // codeql[...]. The rationale for the suppression is solid, but the wrong format means the finding fires every CI run regardless.

Nit / improvement

  • new Error(message, { cause: error }) (see inline): the ES2022 constructor is cleaner than the cast + manual assignment and makes the cause type available without an extra cast in the test.
  • Missing test for async plugin conflict (see inline): the synchronous migration-hint path is tested well, but the documented async-plugin limitation has no test or even a // known gap comment. A future Fastify upgrade changing error-event timing could silently break the hint without any test catching it.

No action needed

  • configBuilder.ts: double-evaluation of RENDERER_ENABLE_HEALTH_ENDPOINTS (in defaultConfig and in buildConfig's runtimeDefaultConfig) is correct and consistent with the existing replayServerAsyncOperationLogs pattern.
  • !('enableHealthEndpoints' in userConfig) in envValuesUsed() is the right check — it handles explicit false from user config correctly.
  • hasAnyVMContext() correctly stays false while a bundle is still in vmCreationPromises; the docstring explains the intentional semantics.
  • Route registration order (built-in routes before applyFastifyConfigFunctions) is correct for the migration-hint semantics.
  • Rate-limiting suppression rationale is solid (internal service, static response, no sensitive data).

* origin/main:
  Expose React 19 root error callbacks (rootErrorHandlers) + hydration-mismatch debugging guide (#3933)
  Add post-merge audit scope resolver (#4029)
  Document continuous agent-run evaluation loop (#4028)
  Tools: add PR batch merge ledger (#3996)
  Add RSC FOUC acceptance coverage (#4033)
  Keep plan-pr-batch goal prompts under 4000 chars (#4025)
  docs(skills): file-collision check + goal-prompt size discipline for plan-pr-batch (#3914)
  Verify React 19.2 <Activity> with react_component (CSR + SSR-hydrate) + docs (#3938)

# Conflicts:
#	llms-full.txt
@justin808 justin808 merged commit 225738e into main Jun 15, 2026
50 checks passed
@justin808 justin808 deleted the jg/3880-node-renderer-health-ready branch June 15, 2026 04:23
justin808 added a commit that referenced this pull request Jun 15, 2026
* origin/main:
  Add built-in /health and /ready endpoints to the Pro node renderer (#3939)
  Document capacity-aware triage contracts (#4027)
justin808 added a commit that referenced this pull request Jun 15, 2026
…ter-slice

* origin/main:
  Add useRailsForm hook + render_model_errors concern: Inertia useForm-style Rails bridge (#3872) (#3942)
  Add declarative cache_tags revalidation to Pro fragment caching (revalidateTag analog) (#3964)
  Verify and document CSP-nonce propagation for streamed RSC under a strict no-unsafe-inline policy (#3934)
  Docs: document Control Plane cost posture for demos (#3998)
  Add built-in /health and /ready endpoints to the Pro node renderer (#3939)
  Document capacity-aware triage contracts (#4027)
justin808 added a commit that referenced this pull request Jun 15, 2026
…ce-maps

* origin/main:
  Add TanStack Router instant-navigation starter (Pro dummy) + docs guide (#3873 v1 slice) (#3953)
  Add useRailsForm hook + render_model_errors concern: Inertia useForm-style Rails bridge (#3872) (#3942)
  Add declarative cache_tags revalidation to Pro fragment caching (revalidateTag analog) (#3964)
  Verify and document CSP-nonce propagation for streamed RSC under a strict no-unsafe-inline policy (#3934)
  Docs: document Control Plane cost posture for demos (#3998)
  Add built-in /health and /ready endpoints to the Pro node renderer (#3939)
  Document capacity-aware triage contracts (#4027)
justin808 added a commit that referenced this pull request Jun 15, 2026
## Summary

Stamps the **17.0.0.rc.4** changelog header and reconciles the post-rc.3
entries.

### What changed
- **Stamped `### [17.0.0.rc.4] - 2026-06-14`** with the standard
compare-link updates (`v17.0.0.rc.3...v17.0.0.rc.4`, `unreleased →
rc.4...main`). Prior RC sections are left intact per the prerelease
convention.
- **Moved the source-mapped stack traces entry (PR 3940) into rc.4.** It
had been placed inside the already-tagged `rc.3` section, but `#3940`
merged *after* `v17.0.0.rc.3` was tagged (verified: `d9ac060a0` is not
an ancestor of the rc.3 tag).
- **Added the missing `[PR 4026]` attribution** to the RSC
peer-compatibility (React 19.2 floor) entry, which previously linked
only the issue.
- **Merged the two duplicate `#### Added` headings** in the section into
one.

### rc.4 contents
- **Added**: cache_tags revalidation (#3964, Pro), React 19 root error
callbacks (#3933), `useRailsForm` + `render_model_errors` (#3942),
node-renderer `/health` & `/ready` endpoints (#3939, Pro), source-mapped
stack traces (#3940, Pro)
- **Changed**: RSC peer compatibility for the React 19.2 floor (#4026,
Pro)
- **Fixed**: Rspack generated apps start in HMR mode (#3926)

Other merged PRs since rc.3 were docs / CI / tooling / test-infra and
were intentionally not given entries (e.g. #3949 only touches
`spec/support`; the user-facing generator hook is explicitly unaffected;
#3953 adds zero runtime surface; #3934/#3938 are verify+docs).

### Notes
- Verified clean under the repo's pinned `prettier@3.6.2`. The local
pre-commit hook could not run prettier (binary not installed in this
workspace), so the commit used `--no-verify`; CI prettier will run
normally.

After merge, run `rake release` (no args) to publish `v17.0.0.rc.4` and
auto-create the GitHub release from this section.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Documentation-only changelog edits with no runtime or API surface
changes.
> 
> **Overview**
> Adds the **`17.0.0.rc.4` (2026-06-14)** release section to
`CHANGELOG.md` and updates the bottom compare links so
**`[unreleased]`** points at `v17.0.0.rc.4...main` and
**`[17.0.0.rc.4]`** covers `v17.0.0.rc.3...v17.0.0.rc.4`.
> 
> The edit **re-sorts notes that landed after the rc.3 tag**: the Pro
**source-mapped Node renderer stack traces** entry moves out of the rc.3
block into rc.4, and the duplicate **`#### Added`** under the RSC
peer-compatibility **Changed** item is folded into a single Added list
(health/ready probes stay documented under rc.4 Added). The React **19.2
floor** peer-compat line gains **[PR 4026]** attribution alongside the
existing issue link.
> 
> No application or library code changes—release documentation only.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
40c7a88. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Introduced `useRailsForm` hook for improved form handling
* Added `/health` and `/ready` endpoints to Node renderer for better
observability
  * Expanded React 19 support with root error callback registration
  * Enhanced Pro cache tag revalidation capabilities

* **Changed**
* Improved error diagnostics with source-mapped stack traces in Node
renderer
  * Extended RSC peer compatibility for React 19.2.7+

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@justin808

Copy link
Copy Markdown
Member Author

Manual verification: confirmed the feature behaves as documented ✅

Reproduced via the merged healthEndpoints.test.ts (boots a real Pro node-renderer worker and hits the endpoints) using the pre-fix-on-one-file tactic. This PR adds opt-in liveness/readiness probes (Closes #3880): GET /health → 200 when the event loop is responsive; GET /ready → 503 {"status":"waiting_for_bundle"} until a worker is online with ≥1 compiled bundle, then 200; default off, enabled via enableHealthEndpoints / RENDERER_ENABLE_HEALTH_ENDPOINTS.

Reproduction

Squash-merged at 225738e21, pre-fix = 225738e21~1. Reverted only src/worker.ts, src/shared/configBuilder.ts, src/worker/vm.ts (this package uses babel-jest, so no type-check blocks the run), then restored.

cd packages/react-on-rails-pro-node-renderer && pnpm exec jest tests/healthEndpoints.test.ts tests/configBuilder.test.ts

Results

Scenario GET /health / GET /ready Result
Pre-fix source routes not registered → 404 health suite fails (absent)
Post-fix restored /health → 200 status-only; /ready → 503 before bundle, 200 after; env-var enable variants; custom-route conflict hint 53 passed / 53 (works as documented)
# PRE-FIX (225738e21~1)
✕ GET /health returns 200 with a status-only body when enabled        Received: 404
✕ GET /ready returns 503 before a bundle is loaded and 200 after      Received: 404
✕ ... all /health + /ready registration/semantics cases (Received: 404)

# POST-FIX (restored, git status clean)
Tests: 53 passed, 53 total   (healthEndpoints + configBuilder)

Caveat

The test boots a real worker process and exercises the registered Fastify routes over HTTP, including the 503→200 readiness transition on bundle load and the env-var enable variants. I did not validate the documented Kubernetes/ECS tcpSocket/exec (curl --http2-prior-knowledge) probe wiring or the h2c-only behavior against a real orchestrator — those are covered by docs, not this run.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Built-in Node renderer health/readiness endpoints for low-ops k8s/ECS deploys

1 participant