🐕

本番環境でrails console --sandboxを安易に使ってはいけない理由

2023/01/13に公開

結論

本番環境でbundle exec rails console --sandboxを安易に使ってはいけない理由は、操作したレコードにロックがかかる可能性があるからです。

ロックが広範囲に及ぶと、大規模な障害につながる危険性があります。

rails console --sandboxは何をやっているのか

bundle exec rails console --sandboxをすると、その中でのレコードに対する操作はトランザクションが張られた状態になります。exitでconsoleを抜けたときにロールバックされることで、操作されたレコードは元の状態に戻ります。

ロックやトランザクションについてはRailsのロック制御を完全理解するで解説しています。

具体例

とある会社のエンジニアさんが運用上の都合でbundle exec rails console --sandboxの中でユーザーの名前を更新することを考えます。そのユーザーがWeb上でプロフィール編集しようとしたらどうなるのでしょうか。

まずconsoleの中でユーザー名を更新して、consoleは開いた状態にしておきます。

$ bundle exec rails console --sandbox
[1] pry(main)> user = User.last
  TRANSACTION (2.4ms)  BEGIN
  User Load (5.9ms)  SELECT `users`.* FROM `users` ORDER BY `users`.`id` DESC LIMIT 1
[2] pry(main)> user.update!(first_name: '太郎')
  TRANSACTION (3.4ms)  SAVEPOINT active_record_1
  Student Update (6.2ms)  UPDATE `users` SET `users`.`first_name` = '太郎', `users`.`updated_at` = '2023-01-13 00:02:40' WHERE `users`.`id` = 2244154
  TRANSACTION (0.7ms)  RELEASE SAVEPOINT active_record_1
=> true
[3] pry(main)>

ちょうどそのタイミングでユーザーがWeb上でログインして、プロフィール編集から名前を変更しようとしました。すると30秒ほど待たされたあと500エラーの画面になってしまいました。

console側でトランザクションを張った状態でユーザーにupdateをかけたことでレコードにロックがかかり、実ユーザーがエラーになってしまうという問題が発生してしまいました。

もし仮に全ユーザーに対してconsoleからupdateをかけた場合、全ユーザーがレコード更新を伴う操作ができないという大問題になってしまいます。

まとめ

「どうせ元の状態に戻るから大丈夫だろう」という軽い気持ちでbundle exec rails console --sandboxを使わないようにしましょう。大規模障害に繋がります。

また、DBのロック機構やトランザクションについての正しい知識をつけておきましょう。

というわけで以上です。

Discussion