本番環境でrails console --sandboxを安易に使ってはいけない理由
結論
本番環境で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