読者です 読者をやめる 読者になる 読者になる

CubicLouve

Spring_MTの技術ブログです。https://github.com/SpringMT (http://spring-mt.tumblr.com/ からの移転)

Rails4のtransactionでハマった <- これは私の間違いでした

rails ruby

申し訳ありません この記事完全に自分の間違いでした。

まず、自分のrailsアプリでは、、もろもろの深淵な理由で、モデルを作るときにActiveRecord::Baseを直接継承せずに、全てのモデルに共通で使うモデルを再定義しています。

なぜこんな事をしているかというと、これまた深淵な理由で、connection poolingができないからです。

まあ、そのモデルの基底クラスでゴニョゴニョしているせいで、ActiveRecord::Base使ってDBに繋ぎに行く場合と、モデルからDBに繋ぎに行く場合でコネクションが別々になっていました。

本当に申し訳ないです。。。。

つまりこの問題は、私のrailsアプリのみで起こる問題でした。。。。。

普通にrailsアプリを作っていれば、問題なくロールバックできます。(ActiveRecord::Baseを直接継承して試してみたら問題なくロールバックできました。)

なので↓ の内容は間違いです。










rails4.1でtransactionの処理を下記のように書いてみた。

ActiveRecord::Base.transaction do
  hoge.destory
end

こうすると、transaction内でhoge.destoryの直後に例外起きても、Rollbackしなかった。。。。

Hoge.transaction do
  hoge.destory
end

こうすればOK。

ログみてると、ActiveRecord::Base.transactionのコネクションとhoge.destoryのコネクションが別物のような感じでした。

簡単に調べてみた。

% bundle exec rails console

mysql> show processlist;
+-----+------+-----------+--------------------+---------+------+-------+------------------+
| Id  | User | Host      | db                 | Command | Time | State | Info             |
+-----+------+-----------+--------------------+---------+------+-------+------------------+
| 199 | root | localhost | NULL               | Query   |    0 | init  | show processlist |
| 208 | root | localhost | server_development | Sleep   |    3 |       | NULL             |
+-----+------+-----------+--------------------+---------+------+-------+------------------+
2 rows in set (0.00 sec)

この時一本コネクション張っている

[1] pry(main)> ActiveRecord::Base.connection
mysql> show processlist;
+-----+------+-----------+--------------------+---------+------+-------+------------------+
| Id  | User | Host      | db                 | Command | Time | State | Info             |
+-----+------+-----------+--------------------+---------+------+-------+------------------+
| 199 | root | localhost | NULL               | Query   |    0 | init  | show processlist |
| 208 | root | localhost | server_development | Sleep   |    3 |       | NULL             |
+-----+------+-----------+--------------------+---------+------+-------+------------------+
2 rows in set (0.00 sec)

一本のまま

[2] pry(main)> Hoge.connection
mysql> show processlist;
+-----+------+-----------+--------------------+---------+------+-------+------------------+
| Id  | User | Host      | db                 | Command | Time | State | Info             |
+-----+------+-----------+--------------------+---------+------+-------+------------------+
| 199 | root | localhost | NULL               | Query   |    0 | init  | show processlist |
| 208 | root | localhost | server_development | Sleep   |   86 |       | NULL             |
| 209 | root | localhost | server_development | Sleep   |   24 |       | NULL             |
+-----+------+-----------+--------------------+---------+------+-------+------------------+
3 rows in set (0.00 sec)

んんん増えた。。。。

[3] pry(main)> Foo.connection
mysql> show processlist;
+-----+------+-----------+--------------------+---------+------+-------+------------------+
| Id  | User | Host      | db                 | Command | Time | State | Info             |
+-----+------+-----------+--------------------+---------+------+-------+------------------+
| 199 | root | localhost | NULL               | Query   |    0 | init  | show processlist |
| 208 | root | localhost | server_development | Sleep   |  188 |       | NULL             |
| 209 | root | localhost | server_development | Sleep   |  126 |       | NULL             |
+-----+------+-----------+--------------------+---------+------+-------+------------------+
3 rows in set (0.00 sec)

コレ以上は増えない

ん、増える。。。。

ActiveRecord::Baseとそれを継承したモデルだとコネクション共有してないのかな。

rails3.2.17だとコネクションは増えないので、rails4での挙動っぽい。

この部分が影響してるのかな、(まだ確認していない)

コミットはここらへんかな

ちょっと詳細調べていきます。

追記

  • 2014/04/19

rails 4.0.4でも同じ挙動だった。