Design: invalidate fixture cache when source definition changes
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 30/100
- issue の種類
- 機能追加
- 明瞭さ
- 説明が足りない
- 活発さ
- 活発
- 領域
- backend, databases, performance
調査の方向性
まず Cache、FileCache、Fixture、Runner を読み、Fixture#generate と Cache#exists? がディスク上のデータを再利用するかどうかをどのように判断しているかを追ってください。問題を明らかにした遅延ロードのパスについては #61 を確認してください。実装前に、キャッシュのフィンガープリント、メタデータの保存場所、不一致時の動作、後方互換性の方針についてメンテナーの合意に達することが完了の条件です。
索引モデルが issue の本文から書いたものです。
説明
Context
PR #61 fixed a NoMethodError when child fixtures were saved against a parent whose cache existed on disk but was not mounted in the current process. During review, a reviewer surfaced a deeper, pre-existing concern:
The lazy-load path can silently use stale parent cache data when the parent cache file exists but does not match the current parent fixture definition.
Fixture#generateskips regeneration when@cache.exists? && !force, andCache#exists?treats a disk file as sufficient. The new child-save path reads parent data directly from that file, andActiveRecordCoder#generatemergesparent_data.keysinto the captured model set. No definition digest, mtime check, schema/version key, or parent-definition validation was found inCache,FileCache,Fixture, orRunner.
This was deliberately scoped out of #61 because it is not new behavior — but it is a real correctness gap and warrants a separate design discussion.
Today's behavior
A fixture cache on disk is treated as valid forever, regardless of:
- Changes to the fixture's
Definitionblock in source code. - Changes to the underlying schema (new columns, dropped tables, type changes).
- Changes to
Codersubclasses (new coders registered, customencode/decodeupdated). - Changes to the Rails / Ruby version that wrote the cache.
The only safety nets today are:
- FK verification at mount time (
ActiveRecord.verify_foreign_keys_for_fixtures), which only catches a subset of schema drift and only at load. - Manual
FIXTURE_KIT_PRESERVE_CACHEopt-out anddb:test:prepare.
What needs deciding
1. What identifies a "valid" cache?
Candidates:
- Source digest of the
Definitionblock (and any procs it closes over — likely needsRubyVM::InstructionSequenceor source-location-based hashing). - mtime of the fixture file that declared the fixture. Cheaper, more brittle (touching the file invalidates).
- Schema fingerprint (digest of
db/schema.rb, orActiveRecord::Migration.current_version). - Coder fingerprint (registered coder classes + their source digest).
- FixtureKit version string (cheap, catches gem upgrades).
A useful cache fingerprint is probably a tuple of several of these, not one. The cheapest worthwhile combo is (fixture_kit_version, schema_version).
2. Where does the metadata live?
- New top-level key in the cache JSON (
"meta": { "version": ..., "schema": ..., "definition_digest": ... }). Simple, requires migrating existing caches. - Sidecar
.meta.jsonfile. Avoids touching the existing format. More disk I/O. - Filename suffix (
fixture.json.v2.abc123.json). Visible but ugly.
3. What happens on mismatch?
- Raise with a clear message ("cache version mismatch — regenerate"). Conservative.
- Silently regenerate. Convenient but hides bugs in the fingerprint logic.
- Warn + regenerate. Probably the right middle ground; logging is cheap.
4. Backward compatibility
Existing users have a populated cache directory. Options:
- Treat a cache without a
metablock as version-0 and force regeneration. One-time cost per fixture, no manual migration needed. - Add a CLI / rake task to migrate caches in place.
- Bump major version of the gem and document the cache reset as a breaking change.
Out of scope
- Auto-regeneration logic itself.
Fixture#generate(force:)already exists; this issue is about when to setforce: trueautomatically. - Cross-process locking. Worth tracking but separate.
Why this is filed as a discussion, not a PR
Each of the four questions above has reasonable answers in multiple directions, and the choices interact (a heavier fingerprint is more correct but more expensive; mismatch behavior is shaped by how cheap regeneration is in practice). Picking a strategy unilaterally and shipping a PR risks landing the wrong tradeoff. Looking for maintainer steer on at least Q1 and Q3 before coding.
Related
- #61 — fix for the lazy-load case that surfaced this concern
- #62 — follow-up: wrap corrupt cache errors (also from #61 review)
- 主要言語
- Ruby
- スター
- 181
- フォーク
- 4
- 平均マージ
- 10日 11時間
- マージ済み PR(30日)
- 1
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
Gusto/fixture_kit のほかの issue
-
Clarify cache behavior with parallel test processes対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
Gusto/fixture_kit#80 · コメント 3 件 ·
Gusto/fixture_kit の issue をすべて見る
似ている issue
-
test_rescues_connection_reset_on_issue_comments_lookup fails on master and blocks every pull requestオープン
難易度 1/5 1時間未満 初心者へのやさしさ 91/100
zerocracy/judges-action#3142 ·
メンテナーはふだん 2 日以内に返信
-
Malformed encoded_filters causes a 500, and keeps failing with session persistence対応中かも @officialasishkumar が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 80/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
-
Visual COBOL: missing 11.0 and 12.0, and 9.0 date differs from Rocket Software's lifecycle pageオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
endoflife-date/endoflife.date#11561 ·
メンテナーはふだん 1 日以内に返信