[Rails] Console `reload!` コマンドがExecutorをリセットするように改善
背景
Rails 8.0では#56297でコンソールがExecutorでラップされるようになりました。これにより、Query Cacheが暗黙的に有効化されるなどの副作用が発生していました(#56473で報告)。
コンソールセッションは通常、長時間再利用されるため、Executorのライフサイクルを適切に管理する仕組みが必要でした。本PRでは、reload! コマンド実行時にExecutorもリセットされるように改善されました。
技術的な変更内容
ActiveSupport::Executorに reset オプションを追加
ActiveSupport::Executor#run! メソッドに reset オプションが追加されました。このオプションを true にすると、現在のExecutorコンテキストを一度完了させ、新しいコンテキストを開始します。
def test_run_with_reset_invokes_callbacks_within_wrap
called = []
executor.to_run { called << :run }
executor.to_complete { called << :complete }
executor.wrap do
called << :before_reset
executor.run!(reset: true)
called << :after_reset
end
assert_equal [:run, :before_reset, :complete, :run, :after_reset, :complete], called
end
このテストからわかるように、reset: true を指定すると以下の動作が行われます:
- 現在のExecutorコンテキストの
completeコールバックが実行される - 新しいExecutorコンテキストの
runコールバックが実行される - 外側の
wrapブロック終了時に再度completeコールバックが実行される
Console reload! コマンドの拡張
コンソールの reload! コマンドが、Executorがアクティブな場合にリセットを実行するように変更されました。
def execute
puts "Reloading..."
executor = Rails.application.executor
executor.run!(reset: true) if executor.active?
Rails.application.reloader.reload!
end
重要なポイント:
- Executorがアクティブな場合のみリセットを実行(
if executor.active?) - コードのリロード(
Rails.application.reloader.reload!)の前にExecutorをリセット -
--skip-executorオプション付きで起動した場合は、Executorのリセットはスキップされる
テストケースの追加
2つのテストケースが追加され、動作が保証されています:
def test_reload_command_resets_executor
spawn_console("-e development")
write_prompt "key = Rails.application.executor.active_key; nil"
write_prompt "old_executor_id = ActiveSupport::IsolatedExecutionState[key].object_id; nil"
write_prompt "reload!", "Reloading...\r\n"
write_prompt "ActiveSupport::IsolatedExecutionState[key].object_id != old_executor_id", "=> true"
end
このテストは、reload! 実行後にExecutorの内部状態(IsolatedExecutionState)が新しいオブジェクトに置き換わることを検証しています。
def test_reload_command_does_not_start_executor_when_it_is_not_active
spawn_console("-e development --skip-executor")
write_prompt "Rails.application.executor.active?", "=> false"
write_prompt "reload!", "Reloading...\r\n"
write_prompt "Rails.application.executor.active?", "=> false"
end
このテストは、--skip-executor オプション使用時に reload! がExecutorを起動しないことを確認しています。
実用的な影響
この変更により、以下のようなケースでコンソールの動作がより予測可能になります:
- Query Cacheが有効な状態で長時間作業した後、
reload!でキャッシュ状態をクリアできる - Executorのコールバック(例:ログ出力やメトリクス収集)が適切にリセットされる
- コンソールセッションを再起動せずに、クリーンな状態から作業を再開できる
従来は、これらの状態をリセットするにはコンソールを再起動する必要がありましたが、本変更により reload! コマンドだけで対応可能になりました。