Bug #18453
closedYJIT breaks Rails collection caching
Description
A minimal app that demonstrates this issue is available on GitHub. It has:
- One model,
Post, with a stringtitleattribute. - One controller action,
posts#index, which fetchesPosts in reverse order of creation into@posts. - A root route to
posts#index. - One view,
app/views/posts/index.html.erb, which uses Rails collection rendering and caching as follows:
<ul>
<li><%= render partial: "posts/post", collection: @posts, cached: true %></li>
</ul>
- A partial,
app/views/posts/_post.html.erbas follows:
<% cache post do %>
<li><%= post.title %></li>
<% end %>
I deployed this app to Heroku here. I configured it to use a Redis cache store.
I added 100 posts like so:
$ heroku run rails c
> 100.times do |i|
* Post.create! title: "Post ##{i + 1}"
* end
All requests to the app index, /, show the posts in reverse chronological order as expected, with cold and warm cache:
* Post #100
* Post #99
* Post #98
* Post #97
* Post #96
* Post #95
...
I enabled YJIT by setting the RUBYOPT environment variable to --yjit --yjit-exec-mem-size=32 and restarted the app server. I cleared the Redis cache with heroku run rails r 'Rails.cache.redis.flushall.
The first request to / with cold cache begins repeating Post #1 after #92:
* Post #100
* Post #99
* Post #98
* Post #97
* Post #96
* Post #95
* Post #94
* Post #93
* Post #92
* Post #1
* Post #1
* Post #1
* Post #1
* Post #1
* Post #1
...
All subsequent requests repeat Post #1 100 times:
* Post #1
* Post #1
* Post #1
* Post #1
* Post #1
* Post #1
* Post #1
* Post #1
* Post #1
...
On restart, Post #1 is repeated after #92 for the first request (as in the second-to-last example). Post #1 is repeated 100 times for subsequent requests (as in the last example).
Disabling YJIT and flushing the Redis cache restores the correct behavior.
Rails version: GitHub rails/rails, 7-0-stable branch, revision 499f12f6c03a4114eb649310e65200fe5d894db0