Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Cache not expiring when model has empty update in transaction

オープン
#555 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
35/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
停滞
技術スタック
ruby
領域
backend

調査の方向性

IdentityCache の _run_commit_callbacks メソッドから開始し、@transaction_changed_attributes がどのように設定されるか、また ActiveRecord と ar_transaction_changes が複数の更新に対してどのように after_commit を呼び出すかを追跡します。3 つのトランザクション例を再現し、その後、通常のキャッシュ有効期限処理を後退させることなく、キャッシュが最終的にコミットされたモデルの状態を反映していることを確認します。

索引モデルが issue の本文から書いたものです。

説明

We've encountered a situation where the cache isn't expired if, within a transaction, a model has a "non-update" followed by an update. Here's the code that created a stale cache in our application:

def update_user(id, attributes) # hash
  ApplicationRecord.transaction do
    User.find(id).update(attributes.except(:email))
    update_sign_in_information(id, attributes[:email])
  end
end

def update_sign_in_information(user_id, email)
  user = User.find(user_id)
  user.update(email: email)
  # other stuff
end

If only the email attribute is passed in, this leads to a stale cache. Here are some more examples that demonstrate the bug:

class Tester
  def self.test
    reset
    ApplicationRecord.transaction do
      user = User.first
      user.update({})
      user.update(name: "test2")
    end
    puts "###### user name: #{User.fetch(User.first.id).name}" # test2, good

    reset
    ApplicationRecord.transaction do
      User.first.update({})
      User.first.update(name: "test2")
    end
    puts "###### user name: #{User.fetch(User.first.id).name}" # test1, stale

    reset
    ApplicationRecord.transaction do
      User.first.update(name: "test1")
      User.first.update(name: "test2")
    end
    puts "###### user name: #{User.fetch(User.first.id).name}" # test1, stale

  end

  def self.reset
    User.first.update(name: "test1")
    User.fetch(User.first.id) # fill the cache
  end
end

A similar "bug" exists in ActiveRecord:

class User < ApplicationRecord
  after_commit :print_name

  def print_name
    puts user.name
  end
end

ApplicationRecord.transaction do
  User.first.update(name: "test1")
  User.first.update(name: "test2")
end

# prints test1 after the whole transaction is committed

The bug goes pretty deep and seems to involve the activerecord and ar_transaction_changes gems. Essentially, the @transaction_changed_attributes variable that IdentityCache's _run_commit_callbacks method is checking is attached to the record, but the after_commit callback is only being called on the first instance even if the transaction contains multiple updates. Here's the monkey patch my team is currently considering adding to address the issue, but could lead to performance regressions:

def _run_commit_callbacks
  # if destroyed? || transaction_changed_attributes.present?
    expire_cache
  # end
  super
end
主要言語
Ruby
スター
2k
フォーク
175
PR マージ指標
30日以内にマージされた PR はありません

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

Shopify/identity_cache のほかの issue

Shopify/identity_cache の issue をすべて見る

似ている issue

Ruby の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。