steveklabnik / request_store

Per-request global storage for Rack.
https://github.com/steveklabnik/request_store
MIT License
1.47k stars 87 forks source link

RequestStore.store gets cleared in `middleware` and has shorter life than Thread.current #50

Closed emclab closed 8 years ago

emclab commented 8 years ago

Our Rails 4.2 app has main app plus a few engines. In main menus index action, the user is render menu page after authorized. In our debugger, the routes and models are getting loaded after render in index action. Before loading model definition, the render hits middleware which does RequestStore.clear!:

module RequestStore
 class Middleware
  def initialize(app)
    @app = app
  end

  def call(env)
    RequestStore.begin!
    @app.call(env)
  ensure
    RequestStore.end!
    RequestStore.clear!
  end
end

end

It seems ReqestStore.store does not behave the same as Thread.current and clears itself after each process is over. The problem for us is that the model loading needs to use the token carried in RequestStore.store, it makes ReqeustStore hard to use for model loading because it has been cleared before the model loading.

steveklabnik commented 8 years ago

Hmmm. I am not 100% sure of how to solve this. You're pretty much relying on the behavior we're trying to prevent, but maybe there's a way for the two to work together somehow. It's not totally clear to me how the lifecycle of all of this works out.

emclab commented 8 years ago

What's the criteria for RequestStore to decide clear up the current thread? In render, it hits render' (instrumentation) =>implicit render=>active support/callbacks=> instrumentation =>instrumenter=>rendering=>metal=>router' => 'etag' => conditionalget => head => flash => id => cookies => query_cache => connection_pool => middleware/callbacks => debug_exceptions => logger => 'tagged_logging=>middleware - clearup RequestStore=>runtime=>local_cache_middleware=>lock=>sendfile=>urlmap=>mock_session=>test=>browser=>base=> 'hooks=>example` => Load model definition

It seems that ReqeustStore is cleared up in the middle of a thread.

steveklabnik commented 8 years ago

The intention is "after a request has been completed". But as a middleware, it can only do that at the point in the chain that it's at.

So maybe it's at the wrong point in the chain, and that's the root cause here?

emclab commented 8 years ago

Yes, as you see, the ReqeustStore is cleared before loading model definition in the middle of process. Those are all Rails/Ruby code and should be consider to be one process from redirect_to to load model definition which is the last before displaying the index view

emclab commented 8 years ago

redirect_to should be considered to be one request. Isn't it?

steveklabnik commented 8 years ago

redirect_to should be considered to be one request. Isn't it?

it is not. For example, I just generated a new app, new controller, one action redirects to the other:

Started GET "/" for ::1 at 2016-03-24 18:12:46 -0400
Processing by WelcomeController#index as HTML
Redirected to http://localhost:3000/welcome/show
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)

Started GET "/welcome/show" for ::1 at 2016-03-24 18:12:46 -0400
Processing by WelcomeController#show as HTML
  Rendered welcome/show.html.erb within layouts/application (0.0ms)
Completed 200 OK in 11ms (Views: 10.4ms | ActiveRecord: 0.0ms)

two http requests. The first serves a 302, and then your browser fetches the new url.

emclab commented 8 years ago

It is `render 'user_menus/index'. Not redirect_to. Sorry.

emclab commented 8 years ago

I put a after_action in user menus controller to kill a thread and it kicks in before RequestStore.clear!. So request store is doing what it is supposed to do.

steveklabnik commented 8 years ago

Ah yes, render doesn't make a new request.