Skip to content

Conversation

julienbourdeau
Copy link
Contributor

Context

Some ActiveRecord::PreparedStatementCacheExpired started popping up recently, always during deploy.

ERROR: cached plan must not change result type (ActiveRecord::PreparedStatementCacheExpired)

TL;DR

The DB uses some cache and when a table is modified (adding/removing column) it's invalidate the cache. If this happens in the middle of a transaction, it breaks!

The best solution is to force Rails to list all columns in select queries instead of using SELECT *. The cache will continue to be valid because the "result type" wasn't changed.

Description

ActiveRecord::PreparedStatementCacheExpired
ERROR:  cached plan must not change result type (ActiveRecord::PreparedStatementCacheExpired)

PG::FeatureNotSupported
ERROR:  cached plan must not change result type (PG::FeatureNotSupported)

This is only an issue when the migration happened during an open transaction. Our pods are running during the migration so this happens sometimes. Then, all pods are "restarted" (rolling roll out).

Solution

The only known way to force Rails to list all columns in a select query is to ignore columns. The feature is used to stop using a column before it's removed from the table.

To ensure all models have something in self.ignored_columns we add a fake name to the parent ApplicationRecord. The column doesn't have to exist.

https://flexport.engineering/avoiding-activerecord-preparedstatementcacheexpired-errors-4499a4f961cf
rails/rails#22170

Before / After

It's a little annoying because the query is getting very big and only a little bit is meaningful but it's a small price to pay.

CleanShot 2025-05-14 at 09 28 55@2x

CleanShot 2025-05-14 at 09 29 05@2x

@julienbourdeau julienbourdeau self-assigned this May 14, 2025
@julienbourdeau julienbourdeau force-pushed the feat/ActiveRecord_PreparedStatementCacheExpired branch from 93e0c3e to fe84028 Compare May 14, 2025 07:59
Comment on lines +3 to +5
class ApplicationRecord
self.ignored_columns = []
end
Copy link
Contributor Author

Choose a reason for hiding this comment

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

because maintaining 614 migrations files over many years is so fun 😝

@julienbourdeau
Copy link
Contributor Author

For now, the issue doesn't occur often enough so we won't merge this yet.

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