rails: Error loading cached data after upgrade to 7.1 `dump format error`
We have a Rails 7.0.5.1
app set with config.load_defaults 6.0
When attempting to upgrade to 7.1.0-alpha, with cached data already present in the app (Redis cache) I’m getting an error when Rails attempts to read the data with Marshal.load
in Marshal61WithFallback
(here).
Argument Error
dump format error (user class)
The cached data is correctly identified as 6.1 with Marshal61WithFallback::MARSHAL_SIGNATURE
but fails to load.
I’ve created an example app where you can easily replicate this, (see reproduction instructions below).
From reading recent commits and the CHANGELOG, I can see that @jonathanhefner did make some --recent changes in here, but from what I can see, this should just work, without any necessary cache migration.
Steps to reproduce
git clone https://github.com/matthutchinson/rails-caching-example
cd rails-caching-example
bin/setup
rails db:seed
rails dev:cache
rails server
open https://localhost:3000
# visit page, causing partials to be cached
# stop server
# edit Gemfile, set to use edge rails from gh master
bundle update rails
rails server
open https://localhost:3000
# page errors when loading cached data with dump format error (user class)
Here’s a what the dumped var looks like in my example app and I’m caching partials in high_scores#index
with;
<%= render partial: "high_score", collection: @high_scores, cached: true %>
"\u0004\bo: ActiveSupport::Cache::Entry\t:\v@valueIC:\u001DActionView::OutputBuffer\"\u0001\xAB<div id=\"high_score_1\">\n <p>\n <strong>Game:</strong>\n <a href=\"/high_scores/1\">Tetris</a>\n </p>\n\n <p>\n <strong>Score:</strong>\n 100000\n </p>\n\n</div>\n<hr/>\n\a:\u0006ET:\u000F@html_safeT:\r@versionI\"\u001920230628145327125454\u0006;\bT:\u0010@created_atf\u00060:\u0010@expires_in0"
Expected behavior
Cached partial data should be loaded and displayed without error
Actual behavior
Error raised when loading cached data from Marshal.load
Argument Error
dump format error (user class)
System configuration
Rails version: 7.1.0-alpha
(migrating from 7.0.5.1
)
Ruby version: 3.1.2
and 3.2.0
Other Notes:
- I thought this commit might have been the cause, but reverting to the commit before that, I get the same issue.
- Clearing the cache will fix the issue, but in production, we’d really prefer not to have to do that.
- If clearing the cache is a requirement, we should update the docs and upgrade guide to explain that.
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 19 (17 by maintainers)
Commits related to this issue
- Fix Action View collection caching to store fragments as bare strings Ref: https://github.com/rails/rails/issues/48611 Individual fragments have been cached as bare string since forever, but somehow... — committed to Shopify/rails by byroot a year ago
- Handle outdated Marshal payloads in Cache::Entry Ref: https://github.com/rails/rails/issues/48611 Followup: https://github.com/rails/rails/pull/48663 If the payload is compressed, then it's deserial... — committed to Shopify/rails by byroot 8 months ago
- Handle outdated Marshal payloads in Cache::Entry with 6.1 cache_format Ref: https://github.com/rails/rails/issues/48611 Followup: https://github.com/rails/rails/pull/48663 It's the same logic than h... — committed to Shopify/rails by byroot 8 months ago
@sedubois the fix is in
7-1-stable
now.Yeah, your custom cache store will have to convert the Marshal error into an
ActiveSupport::Cache::DeserializationError
: https://github.com/rails/rails/pull/48663/files#diff-0dbd64061e6262143eb934c41727278edb775d89d42165c79519a3bf3a1d1321R62-R66Part two is here: https://github.com/rails/rails/pull/48663
I’ll merge tomorrow if no-one objects. Once this is merged this should allow you to upgrade seamlessly, however you will see some increase in cache misses when you first roll out.
I just opened part 1 of the fix: https://github.com/rails/rails/pull/48645
The next step is to rescue cache deserialization issues, and treat them as cache misses.
@matthutchinson thanks. I’ll try to find a solution today.
Right now I’m thinking we could do two birds one stone, by caching these fragments as bare strings:
ActionView::OutputBuffer
But either way, that requires to bust these caches, which we can probably do by changing the prefix in https://github.com/rails/rails/blob/c388a4dcf580281aef4e341f87c52956b0b0057a/actionpack/lib/abstract_controller/caching/fragments.rb