[Pro] Reduce tag-index cache work during streaming - #4443
Conversation
|
Warning Review limit reached
Next review available in: 8 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughThis PR defers streamed cache writes until streaming completes, uses write-time cache options for async cache tagging, and batches tag-index reads and updates across multiple tags. ChangesDeferred cache writes and batched tag indexing
Estimated code review effort: 4 (Complex) | ~45 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis PR reduces cache work during React on Rails Pro streaming by batching tag-index reads and deferring stream cache writes until after all queued chunks are drained. The async (non-streaming) path is also simplified to use a single set of write options for both the cache entry and tag registration instead of computing options twice at miss time and completion time.
Confidence Score: 3/5Safe to merge after addressing the unclosed stream risk: a cache store error during flush skips The batch react_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rb — specifically the placement of Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant C as Controller
participant S as Stream module
participant H as Helper (on_complete)
participant Q as Pending Writes Queue
participant SC as StreamCacheWrites
participant RC as Rails.cache
C->>S: stream_view_containing_react_components
S->>S: "init pending_stream_cache_writes = []"
S->>S: drain_streams_concurrently
loop per component chunk
H->>H: on_complete callback fires
H->>Q: "push {cache_key, chunks, tags, raw_options}"
end
S->>SC: flush_pending_stream_cache_writes
loop per pending write
SC->>RC: cache_write_expired? check
SC->>RC: cache_write_options (computed at flush time)
SC->>RC: write(cache_key, chunks, cache_options)
SC->>RC: register_normalized_tags(tags, cache_key, cache_options)
end
S->>S: response.stream.close
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant C as Controller
participant S as Stream module
participant H as Helper (on_complete)
participant Q as Pending Writes Queue
participant SC as StreamCacheWrites
participant RC as Rails.cache
C->>S: stream_view_containing_react_components
S->>S: "init pending_stream_cache_writes = []"
S->>S: drain_streams_concurrently
loop per component chunk
H->>H: on_complete callback fires
H->>Q: "push {cache_key, chunks, tags, raw_options}"
end
S->>SC: flush_pending_stream_cache_writes
loop per pending write
SC->>RC: cache_write_expired? check
SC->>RC: cache_write_options (computed at flush time)
SC->>RC: write(cache_key, chunks, cache_options)
SC->>RC: register_normalized_tags(tags, cache_key, cache_options)
end
S->>S: response.stream.close
|
|
+ci-run-hosted |
Review summarySolid PR overall — the tag-index One correctness concern flagged inline in Nothing else stood out from a security or performance standpoint — the |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2e197c1d8b
ℹ️ 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".
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
react_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rb (1)
106-125: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winKeep cache flush from blocking stream close. If
flush_pending_stream_cache_writesraises here,response.stream.close if close_stream_at_endis skipped and the stream can remain open. Wrap the flush in a best-effort rescue so shutdown still runs.🤖 Prompt for 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. In `@react_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rb` around lines 106 - 125, flush_pending_stream_cache_writes in Stream#drain_streams should not prevent response.stream.close from running when close_stream_at_end is set; if the flush raises, the current rescue path skips stream shutdown and can leave the response open. Update the shutdown flow in react_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rb so the cache flush is best-effort and failures are rescued/logged locally before the close call, while preserving the existing drain_streams_concurrently, `@async_barrier`&.stop, and ensure cleanup behavior.
🤖 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.
Outside diff comments:
In `@react_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rb`:
- Around line 106-125: flush_pending_stream_cache_writes in Stream#drain_streams
should not prevent response.stream.close from running when close_stream_at_end
is set; if the flush raises, the current rescue path skips stream shutdown and
can leave the response open. Update the shutdown flow in
react_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rb so the cache flush
is best-effort and failures are rescued/logged locally before the close call,
while preserving the existing drain_streams_concurrently, `@async_barrier`&.stop,
and ensure cleanup behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7c482a84-f79c-4841-804c-6e62a867423f
📒 Files selected for processing (5)
react_on_rails_pro/app/helpers/react_on_rails_pro_helper.rbreact_on_rails_pro/lib/react_on_rails_pro/cache/tag_index.rbreact_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rbreact_on_rails_pro/spec/dummy/spec/helpers/react_on_rails_pro_helper_spec.rbreact_on_rails_pro/spec/react_on_rails_pro/cache/tag_index_spec.rb
Hosted CI RequestedTriggered 9 workflow(s) for View progress in the Actions tab. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b48626b070
ℹ️ 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".
Review summaryReviewed the tag-index/stream cache-write changes in this PR. Overall the direction is good (batching tag-index reads with Bug: Minor/non-blocking consideration: Everything else looked solid:
|
ReviewThis PR (1) batches tag-index reads across multiple tags via Found two related correctness issues in the new deferred-flush mechanism in 1. def flush(pending_writes)
Array(pending_writes).each do |cache_write|
...
Rails.cache.write(cache_write[:cache_key], cache_write[:chunks], cache_options)
ReactOnRailsPro::Cache.register_normalized_tags(...)
end
rescue StandardError => e
log_failure(e)
endThe The existing spec ("closes the stream when a deferred stream cache write fails after drain") only covers a single pending write failing — it doesn't catch this multi-entry partial-failure regression. 2. A non-disconnect error during streaming skips the flush entirely, losing all completed components' cache writes (react_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rb:117-131) drain_streams_concurrently(parent_task)
write_rsc_stream_observability_mark
flush_pending_stream_cache_writes
...
rescue StandardError
@async_barrier&.stop
raise
end
No test exercises a non-disconnect error from Both issues stem from the same root cause: batching writes into a single deferred list trades per-component write isolation for a single all-or-nothing flush point. Worth considering whether |
Address-review summaryScan scope: full PR history for #4443 after review-fix push Mattered
Optional
Skipped
Next default scan starts after this comment. Say |
Review summaryFocused on Good:
Left inline comments on two points worth a second look:
Also flagged a minor readability nit around the No security issues spotted (cache keys/tags go through the existing digest/normalization path; no new user input is trusted). |
Review summaryThis PR batches tag-index reads ( One correctness issue found (inline comment on
The non-streaming path ( 🤖 Generated with Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6c068519f2
ℹ️ 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".
Review summaryThis PR optimizes Pro's streamed/tagged cache path: it batches tag-index reads with Left 3 inline comments after tracing the deferred-write path end-to-end:
Nothing here blocks merge in my view — #1 is the one worth a closer look before release given it's an untested code path. |
…cache-4316 * origin/main: Replace chalk with picocolors in create-react-on-rails-app (#4411) (#4444) Fix Pro RSC stylesheet stats retry after read failures (#4401) [Pro] Reduce tag-index cache work during streaming (#4443) Warn on truncated Pro RSC parser streams (#4392) # Conflicts: # react_on_rails_pro/app/helpers/react_on_rails_pro_helper.rb
…nsport * origin/main: Unify Pro component cache fetch behavior (#4384) Replace chalk with picocolors in create-react-on-rails-app (#4411) (#4444) Fix Pro RSC stylesheet stats retry after read failures (#4401) [Pro] Reduce tag-index cache work during streaming (#4443) Warn on truncated Pro RSC parser streams (#4392) Report response-start send rejections (#4389) Add cached static RSC helper and diagnostics (#4386) Fix Pro tag revalidation retry after delete failures (#4375) Fix node renderer graceful shutdown restarts (#4400) Improve release-finish dry-run fetch handling (#4441) Flush RSC payloads before incomplete HTML tails (#4379)
…w-boundary * origin/main: (26 commits) [Pro] Extract async props settled chunk writer (#4448) Fix incorrect defer_generated_component_packs = false migration guidance (#4451) Fix Pro renderer transport memory and reuse (#4394) Fix Pro RSC loadable stats retry visibility (#4447) Unify Pro component cache fetch behavior (#4384) Replace chalk with picocolors in create-react-on-rails-app (#4411) (#4444) Fix Pro RSC stylesheet stats retry after read failures (#4401) [Pro] Reduce tag-index cache work during streaming (#4443) Warn on truncated Pro RSC parser streams (#4392) Report response-start send rejections (#4389) Add cached static RSC helper and diagnostics (#4386) Fix Pro tag revalidation retry after delete failures (#4375) Fix node renderer graceful shutdown restarts (#4400) Improve release-finish dry-run fetch handling (#4441) Flush RSC payloads before incomplete HTML tails (#4379) Handle sync RSC route failures as fetch errors (#4393) Delete never-wired RenderRequest/JsCodeBuilder/RenderingStrategy layer (#4414) (#4437) Delegate deprecated base/ shims to capabilities/ instead of cloning (#4413) (#4436) Remove pre-monorepo node-renderer devDep baggage; consolidate test multipart builders (#4435) Preserve streaming LoadError during dependency failures (#4388) ... # Conflicts: # CHANGELOG.md # packages/react-on-rails-pro/src/RSCProvider.tsx # packages/react-on-rails-pro/src/RSCRoute.tsx # packages/react-on-rails-pro/tests/boundedCacheProvider.client.test.tsx # packages/react-on-rails-pro/tests/getReactServerComponent.client.test.ts
Summary:
Tests:
Fixes #4319
Summary by CodeRabbit