RailsでPumaの挙動を確認したかったのだがデバッグするのにRackのMiddlewareが邪魔だったので回避策を検討してみた。
環境
詳細
Railsから見て先頭付近でリクエストを受け付けるところとして最初にApplicationControllerにデバッガを貼ってみたがBacktraceを見ると60行ほどのスタックでPumaからBreakpointまで結構な量のMiddlewareを通過していた。
class ApplicationController < ActionController::Base binding.break end
rails middleware
を打つとnewしたてのRailsアプリでもこれだけのMIddlewareが表示される。これをいちいち遡ってPumaまでたどりくのは面倒だ。
use ActionDispatch::HostAuthorization use Rack::Sendfile use ActionDispatch::Static use ActionDispatch::Executor use ActionDispatch::ServerTiming use ActiveSupport::Cache::Strategy::LocalCache::Middleware use Rack::Runtime use Rack::MethodOverride use ActionDispatch::RequestId use ActionDispatch::RemoteIp use Sprockets::Rails::QuietAssets use Rails::Rack::Logger use ActionDispatch::ShowExceptions use WebConsole::Middleware use ActionDispatch::DebugExceptions use ActionDispatch::ActionableExceptions use ActionDispatch::Reloader use ActionDispatch::Callbacks use ActiveRecord::Migration::CheckPending use ActionDispatch::Cookies use ActionDispatch::Session::CookieStore use ActionDispatch::Flash use ActionDispatch::ContentSecurityPolicy::Middleware use ActionDispatch::PermissionsPolicy::Middleware use Rack::Head use Rack::ConditionalGet use Rack::ETag use Rack::TempfileReaper run MyApp::Application.routes
アプリケーションとしてのRailsにリクエストが届くのがMiddlewareを経過した後なら、Middlewareの中にBreakpointを貼って然るべき場所に登録してやれば良いだろうという事で↓のようなただリクエストを通過させるMiddlewareを作成してBreakpointを設定。
class MyMiddleware def initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) binding.break [status, headers, body] end end
このMiddlewareをconfig/application.rb
から登録すれば良いのだがconfig.middleware.use
を使うとMiddlewareの最後、アプリケーションの直前に挿入されてしまうのでconfig.middleware.insert_before
を使って一番上のMiddlewareの前に登録してやる。
config.middleware.insert_before ActionDispatch::HostAuthorization, MyMiddleware
$ rails middleware use MyApp::Application::MyMiddleware use ActionDispatch::HostAuthorization use Rack::Sendfile ... run MyApp::Application.routes
この状態でRailsのseverを起動して適当なリクエストを送ると先頭に追加したMiddlewareの中でデバッガが実行されてPumaの直後ぐらいにBreakpointが止まってくれる。あとは少しスタックを昇っていけばさほど労せずに目的のPumaまでたどり着ける。
$ backtrace #0 MyApp::Application::MyMiddleware#call(env={"rack.version"=>[1, 6], "rack.errors"=>...) #1 Rails::Engine#call(env={"rack.version"=>[1, 6], "rack.errors"=>...) #2 Puma::Configuration::ConfigMiddleware#call(env={"rack.version"=>[1, 6], "rack.errors"=>...)
感想
軽い気持ちでPumaの挙動を確認しようと思ったらMiddlewareが結構邪魔で、当初回避方法を思いつかずInitializerとして登録したりして右往左往したので同じ轍を踏まないように記録しておく。 最終的にはシンプルな形で解決出来たのでPumaに限らずinsert_beforeの対象を適当なMiddlewareにすれば実際に開発しているアプリでMiddlewareのデバッグもしやすくなったので結果オーライか。