问题
We have a use case for mounting a mock engine to process sessions when developing locally in which a custom session middleware calls the mock engine via Net::http request when a request comes through.
When there is code change, the reloader is triggered and here calls the ActiveSupport::Dependencies
to start unloading. Then the request is pass down to our custom session middleware and the http request is fired.
However since the http request calls to a mountable engine, it goes thought the same middlewares again and the reloader unloads all the dependencies again which cause the first reload to timeout. So the goal is to be able to skip the reload for the second request.
I added the follow code to ActionDispatch::Reloader
here and it does exactly what I wanted.
class Reloader < Executor
def initialize(app, executor)
super(app, executor)
end
def call(env)
request = ActionDispatch::Request.new(env)
return @app.call(env) if skip_request?(request)
super(env)
end
def skip_request?(request)
request.path_info.start_with?('/session')
end
end
Then I want to make this cleaner figured to pull that out completely to a module and just do a swap like this from an initializer
app.config.middleware.swap(::ActionDispatch::Reloader, MyModule::CustomReloaderMiddleware)
Here is the module
require 'action_dispatch'
module MyModule
class CustomReloaderMiddleware < ActionDispatch::Executor
def initialize(app, executor)
@app, @executor = app, executor
end
def call(env)
request = ActionDispatch::Request.new(env)
return @app.call(env) if skip_request?(request)
super(env)
end
def skip_request?(request)
request.path_info.start_with?('/session')
end
end
end
But I ran into a couple issues.
Uncaught exception: wrong number of arguments (given 1, expected 2)
from for the initialize
in MyModule
, when I starts the server. Then I tried the following
#1
def initialize(app, executor = nil)
@app, @executor = app, executor
end
#2
def initialize(app, executor = nil)
@app, @executor = app, ActiveSupport::Reloader
end
Both of them starts the service correctly and I see the request going through this middleware but it does not reload the code.. So I wondered what is the correct way of swapping ActionDispatch::Reloader with a custom reloader ?
回答1:
You need to pass your middleware's additional argument to the swap
call:
app.config.middleware.swap(::ActionDispatch::Reloader, MyModule::CustomReloaderMiddleware, app.reloader)
That's the same argument given when ActionDispatch::Reloader
is first added -- it's the application's reloader, which is a more specifically configured subclass of AS::Reloader (so you were on the right track).
来源:https://stackoverflow.com/questions/51849817/rail-5-swap-actiondispatchreloader-with-a-custom-reloader