rack cache with X-Rack-Cache:miss - ruby-on-rails

I setup rack cache with redis
config.action_dispatch.rack_cache = true
And it works but sometimes (way to often), caching doesn't work as expected. Event though cache headers are properly set Cache-Control:max-age=20, public, s-maxage=600 I see that response headers contain X-Rack-Cache:miss which means that URL was not in cache and it also didn't store the server response into cache store.
URL is like this (has 1 GET param for language):
http://localhost:3000/js/JAYy-euKaergqRsTlrn67w/events.js?lng=es
and if I add extra params or change the lng param to eg 'de' it than stores the response as expected. It seems like it acts a bit randomly.
I noticed this only on development environment - on production i seems like it always work as expected. What could be the reason?

Related

Unable to find the cache key in memcache

I am using gem rabl for building my api response (https://github.com/nesquena/rabl).
In my controller, I have given like this
#cache_key = "rabl/spree/api/home/v2/index-en"
and in my index.rabl file, I gave,
cache #cache_key, expires_in: 15.minutes
I am using memcache for caching using the client Dalli and have deployed the application in heroku. Everything is working as expected. But when I am trying
Rails.cache.fetch('rabl/spree/api/home/v2/index-en')
I am not able to see any value. Why is it like this ? Does rabl append any value to cache key ?

cannot connect to localhost only 127.0.0.1 [duplicate]

Having server issues with an app in Rails 5.0.0.beta2 trying to use ActionCable.
Using localhost:3000 works fine, as that is what most of ActionCable defaults to. But if I try to run the rails server on port 3001, it gives me Request origin not allowed: http://localhost:3001
The ActionCable docs mention using something like ActionCable.server.config.allowed_request_origins = ['http://localhost:3001'] which does work for me if I put it in config.ru
But that seems like a really weird place to put it. I feel like it should be able to go in an initializer file, or my development.rb environment config file.
To further prove my point that it should be allowed to go in there, the setting ActionCable.server.config.disable_request_forgery_protection = true works to ignore request origin, even when I include it in development.rb.
Why would ActionCable.server.config.disable_request_forgery_protection work in development.rb, but ActionCable.server.config.allowed_request_origins doesn't (but does work in config.ru)?
Not a pressing issue, since I have several options as a work around. I just want to know if I'm missing something obvious about how I imagine this should be working.
You can put
Rails.application.config.action_cable.allowed_request_origins = ['http://localhost:3001'] in your development.rb
See https://github.com/rails/rails/tree/master/actioncable#allowed-request-origins for more informations
For my flutter app, request origin was nil. So, needed to add nil in the list.
I have added this code in config/environments/development.rb, and it works!
config.action_cable.allowed_request_origins = [/http:\/\/*/, /https:\/\/*/, /file:\/\/*/, 'file://', nil]
From this answer, you can also add the following code to config/environments/development.rb to allow requests from both http and https:
Rails.application.configure do
# ...
config.action_cable.allowed_request_origins = [%r{https?://\S+}]
end
config.action_cable.allowed_request_origins accepts an array of strings or regular expressions as the documentation states:
Action Cable will only accept requests from specified origins, which
are passed to the server config as an array. The origins can be
instances of strings or regular expressions, against which a check for
the match will be performed.
The regex listed below will match both http and https urls from any domain so be careful when using them. It is just a matter of preference which one to use.
[%r{https?://\S+}] # Taken from this answer
[%r{http[s]?://\S+}]
[%r{http://*}, %r{https://*}]
[/http:\/\/*/, /https:\/\/*/]

Request origin not allowed: http://localhost:3001 when using Rails5 and ActionCable

Having server issues with an app in Rails 5.0.0.beta2 trying to use ActionCable.
Using localhost:3000 works fine, as that is what most of ActionCable defaults to. But if I try to run the rails server on port 3001, it gives me Request origin not allowed: http://localhost:3001
The ActionCable docs mention using something like ActionCable.server.config.allowed_request_origins = ['http://localhost:3001'] which does work for me if I put it in config.ru
But that seems like a really weird place to put it. I feel like it should be able to go in an initializer file, or my development.rb environment config file.
To further prove my point that it should be allowed to go in there, the setting ActionCable.server.config.disable_request_forgery_protection = true works to ignore request origin, even when I include it in development.rb.
Why would ActionCable.server.config.disable_request_forgery_protection work in development.rb, but ActionCable.server.config.allowed_request_origins doesn't (but does work in config.ru)?
Not a pressing issue, since I have several options as a work around. I just want to know if I'm missing something obvious about how I imagine this should be working.
You can put
Rails.application.config.action_cable.allowed_request_origins = ['http://localhost:3001'] in your development.rb
See https://github.com/rails/rails/tree/master/actioncable#allowed-request-origins for more informations
For my flutter app, request origin was nil. So, needed to add nil in the list.
I have added this code in config/environments/development.rb, and it works!
config.action_cable.allowed_request_origins = [/http:\/\/*/, /https:\/\/*/, /file:\/\/*/, 'file://', nil]
From this answer, you can also add the following code to config/environments/development.rb to allow requests from both http and https:
Rails.application.configure do
# ...
config.action_cable.allowed_request_origins = [%r{https?://\S+}]
end
config.action_cable.allowed_request_origins accepts an array of strings or regular expressions as the documentation states:
Action Cable will only accept requests from specified origins, which
are passed to the server config as an array. The origins can be
instances of strings or regular expressions, against which a check for
the match will be performed.
The regex listed below will match both http and https urls from any domain so be careful when using them. It is just a matter of preference which one to use.
[%r{https?://\S+}] # Taken from this answer
[%r{http[s]?://\S+}]
[%r{http://*}, %r{https://*}]
[/http:\/\/*/, /https:\/\/*/]

Rails 3.1 and Http Page Caching

Given that Heroku Cedar doesn't have http caching provided by Varnish I would like to use Rack::Cache.
I have been told that rails 3.1.1 have Rack::Cache active by default, I just need to make sure to have in the configuration:
config.action_controller.perform_caching = true
and I need to pick a cache store, for this experiment I'm using:
config.cache_store = :memory_store
In the action of the page I want to cache I've added the following lines:
response.header['Cache-Control'] = 'public, max-age=300'
response.header['Expires'] = CGI.rfc1123_date(Time.now + 300)
This code used to work fine with Varnish, the first request would return a 200 and the subsequent (for 5 mins) would return a 304.
This doesn't happen with Rails 3.1 and Heroku Cedar Stack.
I do get those headers in the response but subsequent requests returns 200 instead of 304.
What am I doing wrong? Thank you.
As you noted, the Cedar stack doesn't use Varnish. That means a web request will always hit the ruby server.
With that in mind, Rack::Cache will respect your headers and serve the cached content.
However, since the request is actually going past the http layer into the rails app, the response will always be 200 since the cache doesn't happen at the http layer anymore.
To confirm this is true, insert this in one of your cached actions:
<%= Time.now.to_i %>
Then, reload the page several times and you'll notice the timestamp won't change.

Re-entrant subrequests in Rack/Rails

I've got a couple Engine plugins with metal endpoints that implement some extremely simple web services I intend to share across multiple applications. They work just fine as they are, but obviously, while loading them locally for development and testing, sending Net::HTTP a get_response message to ask localhost for another page from inside the currently executing controller object results in instant deadlock.
So my question is, does Rails' (or Rack's) routing system provide a way to safely consume a web service which may or may not be a part of the same app under the same server instance, or will I have to hack a special case together with render_to_string for those times when the hostname in the URI matches my own?
It doesn't work in development because it's only serving one request at a time, and the controller's request gets stuck. If you need this you can run multiple server locally behind a load balancer. I recommend using Passenger even for development (and the prefpane if you are on OS X).
My recommendation for you is to separate the internal web services and the applications that use them. This way you do not duplicate the code and you can easily scale and control them individually.
This is in fact possible. However, you need to ensure that the services you call are not calling each other recursively.
A really simple "reentrant" Rack middleware could work like this:
class Reentry < Struct.new(:app)
def call(env)
#current_env = env
app.call(env.merge('reentry' => self)
end
def call_rack(request_uri)
env_for_recursive_call = #current_env.dup
env_for_recursive_call['PATH_INFO'] = request_uri # ...and more
status, headers, response = call(env_for_recursive_call)
# for example, return response as a String
response.inject(''){|part, buf| part + buf }
end
end
Then in the calling code:
env['reentry'].call_rack('/my/api/get-json')
A very valid use case for this is sideloading API responses in JSON
format within your main page.
Obviously the success of this technique will depend on the sophistication
of your Rack stack (as some parts of the Rack env will not like being reused).

Resources